rpcsx/rpcs3/Loader/TAR.cpp
Cornee Traas 458dbbd15d PS3UPDAT.PUP installer (#2386)
* Add PUP loader

* Add .tar loader and update .pup loader

* Add extract method + offset to TAR loader

Also adds error checking + operator bool overload

* Add firmware decryption keys to key vault

* Initial seperation of SELFDecrypter

This seperates SELFDecrypter into itself and SCEDecrypter.
SCEDecrypter contains the logic to decrypt any file with an SCE Header.
SELFDecrypter inherits from SCEDecrypter and contains the code
specifically to do with ELF. DecryptData could be deduplicated more.

* Add "Install Firmware" option to tools menu

* SCEDecrypter: put each segment in own file

Also, const-correctness, adjusted buffer size and better error handling

* More SELFDecrypter refactoring

* Compile fix

* Add messageboxes to firmware install

* Add progress bar to firmware install
2017-02-16 10:15:00 +08:00

124 lines
2.9 KiB
C++

#include "stdafx.h"
#include "TAR.h"
#include <cmath>
#include <cstdlib>
tar_object::tar_object(const fs::file& file, size_t offset) : m_file(file), initial_offset(offset)
{
m_file.seek(initial_offset);
largest_offset = initial_offset;
}
TARHeader tar_object::read_header(u64 offset)
{
m_file.seek(offset);
TARHeader header;
m_file.read(header);
return header;
}
int octalToDecimal(int octalNumber)
{
int decimalNumber = 0, i = 0, rem;
while (octalNumber != 0)
{
rem = octalNumber % 10;
octalNumber /= 10;
decimalNumber += rem * pow(8, i);
++i;
}
return decimalNumber;
}
std::vector<std::string> tar_object::get_filenames()
{
if (!isValid) return std::vector<std::string>();
std::vector<std::string> vec;
get_file("");
for (auto it = m_map.cbegin(); it != m_map.cend(); ++it)
{
vec.push_back(it->first);
}
return vec;
}
fs::file tar_object::get_file(std::string path)
{
if (!isValid || !m_file) return fs::file();
auto it = m_map.find(path);
if (it != m_map.end())
{
TARHeader header = read_header(it->second);
int size = octalToDecimal(atoi(header.size));
std::vector<u8> buf(size);
m_file.read(buf, size);
int offset = ((m_file.pos() - initial_offset + 512 - 1) & ~(512 - 1)) + initial_offset; // Always keep the offset aligned to 512 bytes + the initial offset.
m_file.seek(offset);
return fs::make_stream(std::move(buf));
}
else //continue scanning from last file entered
{
while (m_file.pos() < m_file.size()) {
TARHeader header = read_header(largest_offset);
if (!isValid) return fs::file();
if (std::string(header.magic).find("ustar") != std::string::npos)
m_map[header.name] = largest_offset;
int size = octalToDecimal(atoi(header.size));
if (path.compare(header.name) == 0) { //path is equal, read file and advance offset to start of next block
std::vector<u8> buf(size);
m_file.read(buf, size);
int offset = ((m_file.pos() - initial_offset + 512 - 1) & ~(512 - 1)) + initial_offset;
m_file.seek(offset);
largest_offset = offset;
return fs::make_stream(std::move(buf));
}
else { // just advance offset to next block
m_file.seek(size, fs::seek_mode::seek_cur);
int offset = ((m_file.pos() - initial_offset + 512 - 1) & ~(512 - 1)) + initial_offset;
m_file.seek(offset);
largest_offset = offset;
}
}
return fs::file();
}
}
bool tar_object::extract(std::string path)
{
if (!isValid || !m_file) return false;
get_file(""); //Make sure we have scanned all files
for (auto iter : m_map)
{
TARHeader header = read_header(iter.second);
if (std::string(header.name).empty()) continue;
switch (header.filetype) {
case '0':
{
fs::file file(header.name, fs::rewrite);
file.write(get_file(header.name).to_vector<u8>());
break;
}
case '5':
{
fs::create_dir(path + header.name);
break;
}
default:
LOG_ERROR(GENERAL,"Tar loader: unknown file type: "+header.filetype);
return false;
}
}
return true;
}