-
Notifications
You must be signed in to change notification settings - Fork 3
/
pakfile.cpp
118 lines (105 loc) · 3.67 KB
/
pakfile.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "pakfile.h"
#include <stdexcept>
#include <iterator>
#include <algorithm>
#include <cstring>
namespace scpak
{
BadPakException::BadPakException(const char *what) :
BaseException(), what_(what)
{ }
const char * BadPakException::what() const
{
return what_.c_str();
}
void PakFile::load(std::istream &stream)
{
// read header
PakHeader header;
stream.read(reinterpret_cast<char*>(&header), sizeof(header));
if (!header.checkMagic())
throw BadPakException("invalid pak header");
StreamBinaryReader reader(&stream);
// read content dictionary
for (int i = 0; i<header.contentCount; ++i)
{
PakItem item;
item.name = reader.readString();
item.type = reader.readString();
item.offset = reader.readInt32();
item.length = reader.readInt32();
addItem(std::move(item));
}
// read all contents
for (PakItem &item : m_contents)
{
stream.seekg(header.contentOffset + item.offset, std::ios::beg);
item.data.resize(item.length);
stream.read(reinterpret_cast<char*>(item.data.data()), item.length);
item.offset = -1; // we will not be able to access the stream
}
}
void PakFile::save(std::ostream &stream)
{
// write file header for the first time
PakHeader header;
header.contentCount = m_contents.size();
StreamBinaryWriter writer(&stream);
stream.write(reinterpret_cast<char*>(&header), sizeof(header));
// we do not know where the content will locate, so it is also
// necessary to write content dictionary twice
// write content dictionary for the first time
for (const PakItem &item : m_contents)
{
writer.writeString(item.name);
writer.writeString(item.type);
writer.writeInt(item.offset); // should be -1
writer.writeInt(item.length);
}
header.contentOffset = stream.tellp();
// write content items
for (PakItem &item : m_contents)
{
// there is a magic number before every content data in origin Content.pak
// it's DEADBEEF
stream.put(0xDE);
stream.put(0xAD);
stream.put(0xBE);
stream.put(0xEF);
item.offset = static_cast<int>(stream.tellp()) - header.contentOffset;
stream.write(reinterpret_cast<char*>(item.data.data()), item.length);
}
// write the header again
stream.seekp(0, std::ios::beg);
stream.write(reinterpret_cast<char*>(&header), sizeof(header));
// write content dictionary again
for (PakItem &item : m_contents)
{
writer.writeString(item.name);
writer.writeString(item.type);
writer.writeInt(item.offset);
writer.writeInt(item.length);
item.offset = -1; // as items can be modified, it is meaningless to keep a offset
}
}
const std::vector<PakItem>& PakFile::contents() const
{
return m_contents;
}
void PakFile::addItem(const PakItem &item)
{
m_contents.push_back(item);
}
void PakFile::addItem(PakItem &&item)
{
m_contents.push_back(std::move(item));
}
PakItem& PakFile::getItem(std::size_t where)
{
return m_contents.at(where);
}
void PakFile::removeItem(std::size_t where)
{
m_contents.erase(m_contents.begin() + where);
}
}