diff --git a/source/utils/extract.cpp b/source/utils/extract.cpp index c5ad8e0..0bf3a39 100644 --- a/source/utils/extract.cpp +++ b/source/utils/extract.cpp @@ -39,81 +39,67 @@ u64 extractSize = 0; u64 writeOffset = 0; Result extractArchive(std::string archivePath, std::string wantedFile, std::string outputPath) { - extractSize = 0; - writeOffset = 0; - - archive_entry *entry; + extractSize = 0, writeOffset = 0, filesExtracted = 0; archive *a = archive_read_new(); + archive_entry *entry; + int flags; + + /* Select which attributes we want to restore. */ + flags = ARCHIVE_EXTRACT_TIME; + flags |= ARCHIVE_EXTRACT_PERM; + flags |= ARCHIVE_EXTRACT_ACL; + flags |= ARCHIVE_EXTRACT_FFLAGS; + + a = archive_read_new(); archive_read_support_format_all(a); - archive_read_support_format_raw(a); if(archive_read_open_filename(a, archivePath.c_str(), 0x4000) != ARCHIVE_OK) { - Logging::writeToLog("EXTRACT_ERROR_ARCHIVE"); - return EXTRACT_ERROR_ARCHIVE; + return EXTRACT_ERROR_OPENFILE; } - Result ret = EXTRACT_ERROR_FIND; while(archive_read_next_header(a, &entry) == ARCHIVE_OK) { - std::string entryName(archive_entry_pathname(entry)); - std::smatch match; - if(std::regex_search(entryName, match, std::regex(wantedFile))) { - extractingFile = (entryName.length() > wantedFile.length() ? entryName.substr(wantedFile.length()) : wantedFile); - ret = EXTRACT_ERROR_NONE; - - // make directories - std::string out = (outputPath + match.suffix().str()); - int substrPos = 1; - while(out.find("/", substrPos)) { - mkdir(out.substr(0, substrPos).c_str(), 0777); - Logging::writeToLog(out.substr(0, substrPos)); - substrPos = out.find("/", substrPos)+1; - } - - Handle fileHandle; - Result res = openFile(&fileHandle, (outputPath + match.suffix().str()).c_str(), true); - if (R_FAILED(res)) { - Logging::writeToLog("EXTRACT_ERROR_OPENFILE"); - ret = EXTRACT_ERROR_OPENFILE; - break; - } - u64 fileSize = archive_entry_size(entry); - extractSize = fileSize; // Get Size. - u32 toRead = 0x30000; - u8 * buf = (u8 *)memalign(0x1000, toRead); - if (buf == NULL) { - Logging::writeToLog("EXTRACT_ERROR_ALLOC"); - ret = EXTRACT_ERROR_ALLOC; - FSFILE_Close(fileHandle); - break; - } - - u32 bytesWritten = 0; - writeOffset = 0; - do { - if (toRead > fileSize) toRead = fileSize; - ssize_t size = archive_read_data(a, buf, toRead); - if (size < 0) { - Logging::writeToLog("EXTRACT_ERROR_READFILE"); - ret = EXTRACT_ERROR_READFILE; - break; - } - res = FSFILE_Write(fileHandle, &bytesWritten, writeOffset, buf, toRead, 0); - if (R_FAILED(res)) { - Logging::writeToLog("EXTRACT_ERROR_WRITEFILE"); - ret = EXTRACT_ERROR_WRITEFILE; - break; + if(archive_entry_size(entry) > 0) { // Ignore folders + std::smatch match; + std::string entryName(archive_entry_pathname(entry)); + if(std::regex_search(entryName, match, std::regex(wantedFile))) { + extractingFile = outputPath + match.suffix().str(); + + // make directories + int substrPos = 1; + while(extractingFile.find("/", substrPos)) { + mkdir(extractingFile.substr(0, substrPos).c_str(), 0777); + substrPos = extractingFile.find("/", substrPos) + 1; } - writeOffset += bytesWritten; - fileSize -= bytesWritten; - } while(fileSize); - FSFILE_Close(fileHandle); - free(buf); - filesExtracted++; + uint sizeLeft = archive_entry_size(entry); + extractSize = sizeLeft; + writeOffset = 0; + FILE *file = fopen(extractingFile.c_str(), "wb"); + if(!file) { + return EXTRACT_ERROR_WRITEFILE; + } + + u8 *buf = new u8[0x30000]; + if(buf == nullptr) { + return EXTRACT_ERROR_ALLOC; + } + + while(sizeLeft > 0) { + u64 toRead = std::min(0x30000u, sizeLeft); + ssize_t size = archive_read_data(a, buf, toRead); + fwrite(buf, 1, size, file); + sizeLeft -= size; + writeOffset += size; + filesExtracted++; + } + fclose(file); + delete[] buf; + } } } + archive_read_close(a); archive_read_free(a); - return ret; + return EXTRACT_ERROR_NONE; } \ No newline at end of file