Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/nall/bps/linear.hpp
2 views
1
#ifndef NALL_BPS_LINEAR_HPP
2
#define NALL_BPS_LINEAR_HPP
3
4
#include <nall/crc32.hpp>
5
#include <nall/file.hpp>
6
#include <nall/filemap.hpp>
7
#include <nall/stdint.hpp>
8
#include <nall/string.hpp>
9
10
namespace nall {
11
12
struct bpslinear {
13
inline void source(const uint8_t *data, unsigned size);
14
inline void target(const uint8_t *data, unsigned size);
15
16
inline bool source(const string &filename);
17
inline bool target(const string &filename);
18
inline bool create(const string &filename, const string &metadata = "");
19
20
protected:
21
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
22
enum : unsigned { Granularity = 1 };
23
24
filemap sourceFile;
25
const uint8_t *sourceData;
26
unsigned sourceSize;
27
28
filemap targetFile;
29
const uint8_t *targetData;
30
unsigned targetSize;
31
};
32
33
void bpslinear::source(const uint8_t *data, unsigned size) {
34
sourceData = data;
35
sourceSize = size;
36
}
37
38
void bpslinear::target(const uint8_t *data, unsigned size) {
39
targetData = data;
40
targetSize = size;
41
}
42
43
bool bpslinear::source(const string &filename) {
44
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
45
source(sourceFile.data(), sourceFile.size());
46
return true;
47
}
48
49
bool bpslinear::target(const string &filename) {
50
if(targetFile.open(filename, filemap::mode::read) == false) return false;
51
target(targetFile.data(), targetFile.size());
52
return true;
53
}
54
55
bool bpslinear::create(const string &filename, const string &metadata) {
56
file modifyFile;
57
if(modifyFile.open(filename, file::mode::write) == false) return false;
58
59
uint32_t modifyChecksum = ~0;
60
unsigned targetRelativeOffset = 0, outputOffset = 0;
61
62
auto write = [&](uint8_t data) {
63
modifyFile.write(data);
64
modifyChecksum = crc32_adjust(modifyChecksum, data);
65
};
66
67
auto encode = [&](uint64_t data) {
68
while(true) {
69
uint64_t x = data & 0x7f;
70
data >>= 7;
71
if(data == 0) {
72
write(0x80 | x);
73
break;
74
}
75
write(x);
76
data--;
77
}
78
};
79
80
unsigned targetReadLength = 0;
81
82
auto targetReadFlush = [&]() {
83
if(targetReadLength) {
84
encode(TargetRead | ((targetReadLength - 1) << 2));
85
unsigned offset = outputOffset - targetReadLength;
86
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
87
}
88
};
89
90
write('B');
91
write('P');
92
write('S');
93
write('1');
94
95
encode(sourceSize);
96
encode(targetSize);
97
98
unsigned markupSize = metadata.length();
99
encode(markupSize);
100
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
101
102
while(outputOffset < targetSize) {
103
unsigned sourceLength = 0;
104
for(unsigned n = 0; outputOffset + n < min(sourceSize, targetSize); n++) {
105
if(sourceData[outputOffset + n] != targetData[outputOffset + n]) break;
106
sourceLength++;
107
}
108
109
unsigned rleLength = 0;
110
for(unsigned n = 1; outputOffset + n < targetSize; n++) {
111
if(targetData[outputOffset] != targetData[outputOffset + n]) break;
112
rleLength++;
113
}
114
115
if(rleLength >= 4) {
116
//write byte to repeat
117
targetReadLength++;
118
outputOffset++;
119
targetReadFlush();
120
121
//copy starting from repetition byte
122
encode(TargetCopy | ((rleLength - 1) << 2));
123
unsigned relativeOffset = (outputOffset - 1) - targetRelativeOffset;
124
encode(relativeOffset << 1);
125
outputOffset += rleLength;
126
targetRelativeOffset = outputOffset - 1;
127
} else if(sourceLength >= 4) {
128
targetReadFlush();
129
encode(SourceRead | ((sourceLength - 1) << 2));
130
outputOffset += sourceLength;
131
} else {
132
targetReadLength += Granularity;
133
outputOffset += Granularity;
134
}
135
}
136
137
targetReadFlush();
138
139
uint32_t sourceChecksum = crc32_calculate(sourceData, sourceSize);
140
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n);
141
uint32_t targetChecksum = crc32_calculate(targetData, targetSize);
142
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
143
uint32_t outputChecksum = ~modifyChecksum;
144
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
145
146
modifyFile.close();
147
return true;
148
}
149
150
}
151
152
#endif
153
154