Add lua functions to manipulate emulator settings
[lsnes.git] / rrdata.cpp
blob36de6921f8fd3d7b290341de4b292d59204f572c
1 #include "rrdata.hpp"
2 #include <set>
3 #include <cstring>
4 #include <string>
5 #include <iostream>
6 #include <fstream>
7 #include <sstream>
8 #include "misc.hpp"
11 // XABCDEFXXXXXXXXX
12 // 0123456789XXXXXX
14 // ABCDEF0123456789XXXXXX
16 rrdata::instance::instance() throw(std::bad_alloc)
18 std::string rnd = get_random_hexstring(2 * RRDATA_BYTES);
19 memset(bytes, 0, RRDATA_BYTES);
20 for(unsigned i = 0; i < 2 * RRDATA_BYTES; i++) {
21 unsigned x = rnd[i];
22 x = x & 0x1F;
23 x = x - x / 16 * 9 - 1;
24 bytes[i / 2] = 16 * bytes[i / 2] + x;
28 rrdata::instance::instance(unsigned char* b) throw()
30 memcpy(bytes, b, RRDATA_BYTES);
33 bool rrdata::instance::operator<(const struct instance& i) const throw()
35 for(unsigned j = 0; j < RRDATA_BYTES; j++)
36 if(bytes[j] < i.bytes[j])
37 return true;
38 else if(bytes[j] > i.bytes[j])
39 return false;
40 return false;
43 bool rrdata::instance::operator==(const struct instance& i) const throw()
45 for(unsigned j = 0; j < RRDATA_BYTES; j++)
46 if(bytes[j] != i.bytes[j])
47 return false;
48 return true;
51 const struct rrdata::instance rrdata::instance::operator++(int) throw()
53 instance i = *this;
54 ++*this;
55 return i;
58 const struct rrdata::instance& rrdata::instance::operator++() throw()
60 unsigned carry = 1;
61 for(unsigned i = 31; i < 32; i--) {
62 unsigned newcarry = (bytes[i] == 255 && carry);
63 bytes[i] += carry;
64 carry = newcarry;
66 return *this;
69 namespace
71 std::set<rrdata::instance> rrset;
72 std::ifstream ihandle;
73 std::ofstream ohandle;
74 bool handle_open;
75 std::string current_project;
78 void rrdata::read_base(const std::string& project) throw(std::bad_alloc)
80 if(project == current_project)
81 return;
82 std::set<rrdata::instance> new_rrset;
83 std::string filename = get_config_path(NULL) + "/" + project + ".rr";
84 if(handle_open) {
85 ohandle.close();
86 handle_open = false;
88 ihandle.open(filename.c_str(), std::ios_base::in);
89 while(ihandle) {
90 unsigned char bytes[RRDATA_BYTES];
91 ihandle.read(reinterpret_cast<char*>(bytes), RRDATA_BYTES);
92 instance k(bytes);
93 //std::cerr << "Loaded symbol: " << k << std::endl;
94 new_rrset.insert(k);
96 ihandle.close();
97 ohandle.open(filename.c_str(), std::ios_base::out | std::ios_base::app);
98 if(ohandle)
99 handle_open = true;
100 rrset = new_rrset;
101 current_project = project;
104 void rrdata::close() throw()
106 current_project = "";
107 if(handle_open)
108 ohandle.close();
109 handle_open = false;
112 void rrdata::add(const struct rrdata::instance& i) throw(std::bad_alloc)
114 if(rrset.insert(i).second) {
115 //std::cerr << "New symbol: " << i << std::endl;
116 ohandle.write(reinterpret_cast<const char*>(i.bytes), RRDATA_BYTES);
117 ohandle.flush();
121 void rrdata::add_internal() throw(std::bad_alloc)
123 if(!internal)
124 internal = new instance();
125 add((*internal)++);
128 namespace
130 void flush_symbol(std::ostream& strm, const rrdata::instance& base, const rrdata::instance& predicted,
131 unsigned count)
133 char opcode;
134 char buf1[RRDATA_BYTES + 4];
135 char buf2[3];
136 unsigned bias;
137 if(count == 1) {
138 opcode = 0x00;
139 bias = 1;
140 } else if(count < 258) {
141 opcode = 0x20;
142 bias = 2;
143 } else if(count < 65794) {
144 opcode = 0x40;
145 bias = 258;
146 } else {
147 opcode = 0x60;
148 bias = 65794;
150 unsigned j;
151 for(j = 0; j < 31; j++)
152 if(base.bytes[j] != predicted.bytes[j])
153 break;
154 opcode += j;
155 buf1[0] = opcode;
156 memcpy(buf1 + 1, base.bytes + j, RRDATA_BYTES - j);
157 buf2[0] = (count - bias) >> 16;
158 buf2[1] = (count - bias) >> 8;
159 buf2[2] = (count - bias);
160 memcpy(buf1 + (RRDATA_BYTES - j + 1), buf2 + (3 - (opcode >> 5)), opcode >> 5);
161 strm.write(buf1, (RRDATA_BYTES - j + 1) + (opcode >> 5));
162 //std::cerr << "Encoding " << count << " symbols starting from " << base << std::endl;
166 uint64_t rrdata::write(std::ostream& strm) throw(std::bad_alloc)
168 uint64_t count = 0;
169 instance last_encode_end;
170 memset(last_encode_end.bytes, 0, RRDATA_BYTES);
172 instance predicted;
173 instance encode_base;
174 unsigned encode_count = 0;
175 for(auto i = rrset.begin(); i != rrset.end(); i++) {
176 //std::cerr << "Considering " << *i << std::endl;
177 count++;
178 if(encode_count == 0) {
179 //This is the first symbol.
180 encode_base = *i;
181 encode_count = 1;
182 } else if(predicted == *i && encode_count < 16843009) {
183 //Correct prediction.
184 encode_count++;
185 } else {
186 //Failed prediction
187 flush_symbol(strm, encode_base, last_encode_end, encode_count);
188 last_encode_end = predicted;
189 encode_base = *i;
190 encode_count = 1;
192 predicted = *i;
193 ++predicted;
195 if(encode_count > 0)
196 flush_symbol(strm, encode_base, last_encode_end, encode_count);
197 return count;
200 uint64_t rrdata::read(std::istream& strm) throw(std::bad_alloc)
202 uint64_t count = 0;
203 instance decoding;
204 memset(decoding.bytes, 0, RRDATA_BYTES);
205 while(strm) {
206 char opcode;
207 char buf1[RRDATA_BYTES];
208 char buf2[3];
209 strm.read(&opcode, 1);
210 if(!strm)
211 continue;
212 unsigned validbytes = (opcode & 0x1F);
213 unsigned lengthbytes = (opcode & 0x60) >> 5;
214 unsigned repeat = 1;
215 strm.read(buf1, RRDATA_BYTES - validbytes);
216 memcpy(decoding.bytes + validbytes, buf1, RRDATA_BYTES - validbytes);
217 if(lengthbytes > 0)
218 strm.read(buf2, lengthbytes);
219 if(lengthbytes == 1)
220 repeat = 2 + buf2[0];
221 if(lengthbytes == 2)
222 repeat = 258 + static_cast<unsigned>(buf2[0]) * 256 + buf2[1];
223 if(lengthbytes == 3)
224 repeat = 65794 + static_cast<unsigned>(buf2[0]) * 65536 + static_cast<unsigned>(buf2[1]) *
225 256 + buf2[2];
226 //std::cerr << "Decoding " << count << " symbols starting from " << decoding << std::endl;
227 for(unsigned i = 0; i < repeat; i++)
228 rrdata::add(decoding++);
229 count += repeat;
231 return count;
234 const char* hexes = "0123456789ABCDEF";
236 std::ostream& operator<<(std::ostream& os, const struct rrdata::instance& j)
238 for(unsigned i = 0; i < 32; i++) {
239 os << hexes[j.bytes[i] / 16] << hexes[j.bytes[i] % 16];
241 return os;
244 rrdata::instance* rrdata::internal;
247 //DBC0AB8CBAAC6ED4B7781E34057891E8B9D93AAE733DEF764C06957FF705DE00
248 //DBC0AB8CBAAC6ED4B7781E34057891E8B9D93AAE733DEF764C06957FF705DDF3