rpcsx/rpcs3/Loader/TAR.cpp

124 lines
2.9 KiB
C++
Raw Normal View History

#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;
}