mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-23 18:11:28 +02:00
Compare commits
55 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
064ca4c626 | ||
|
10906d8418 | ||
|
e88ab60663 | ||
|
564e38ea9f | ||
|
0c3f0834ab | ||
|
f38af85e0a | ||
|
8276700381 | ||
|
ec69109c0b | ||
|
8ae6444af7 | ||
|
5fc86eae6d | ||
|
927c97eb06 | ||
|
cf09d41669 | ||
|
724747ac9e | ||
|
e1e275eb38 | ||
|
e30fcade43 | ||
|
42dbf73d18 | ||
|
2a90e12999 | ||
|
d129b72ced | ||
|
bc0b86891a | ||
|
52443936e6 | ||
|
6694a1c986 | ||
|
7ffaeb2ac1 | ||
|
67e6a6e742 | ||
|
9a3650c6ab | ||
|
0a3d6e4c53 | ||
|
378b78dad7 | ||
|
721e0b1762 | ||
|
2bf3dbf375 | ||
|
396003e7f6 | ||
|
a92a554d7b | ||
|
9ea35ce569 | ||
|
348bace8ed | ||
|
5cbf5b617b | ||
|
d5cd21eb0c | ||
|
8b7dd89059 | ||
|
6c4e3ec790 | ||
|
8d64f9b155 | ||
|
bc5fd8c53c | ||
|
64072325c4 | ||
|
017f9926fc | ||
|
c31543ea58 | ||
|
7c3aaf12b0 | ||
|
3fad0a0105 | ||
|
72a2967eeb | ||
|
a8ee35633c | ||
|
7dda70baa4 | ||
|
2c61ce2522 | ||
|
266495b475 | ||
|
133d568f76 | ||
|
b433838e9f | ||
|
a3abe8ebaa | ||
|
f88ef9e9a2 | ||
|
a136378a7b | ||
|
012cdd4b14 | ||
|
eecc085e42 |
@@ -3,6 +3,9 @@ snes := snes
|
||||
gameboy := gameboy
|
||||
profile := accuracy
|
||||
ui := ui
|
||||
# phoenix := gtk
|
||||
|
||||
# options += debugger
|
||||
|
||||
# compiler
|
||||
c := $(compiler) -std=gnu99
|
||||
@@ -18,6 +21,8 @@ objects := libco
|
||||
# profile-guided optimization
|
||||
# flags += -fprofile-use
|
||||
|
||||
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
|
||||
|
||||
# platform
|
||||
ifeq ($(platform),x)
|
||||
link += -s -ldl -lX11 -lXext
|
||||
@@ -65,6 +70,6 @@ clean:
|
||||
-@$(call delete,*.manifest)
|
||||
|
||||
archive-all:
|
||||
tar -cjf bsnes.tar.bz2 data gameboy libco nall obj out phoenix ruby snes ui ui-gameboy Makefile cc.bat clean.bat sync.sh
|
||||
tar -cjf bsnes.tar.bz2 data gameboy libco nall obj out phoenix ruby snes ui ui-gameboy ui-libsnes Makefile cc.bat clean.bat sync.sh
|
||||
|
||||
help:;
|
||||
|
@@ -1,2 +1,2 @@
|
||||
@mingw32-make -j 2
|
||||
@mingw32-make -j 8
|
||||
@pause
|
||||
|
1228
bsnes/data/bsnes-logo.hpp
Executable file
1228
bsnes/data/bsnes-logo.hpp
Executable file
File diff suppressed because it is too large
Load Diff
115578
bsnes/data/cheats.xml
115578
bsnes/data/cheats.xml
File diff suppressed because it is too large
Load Diff
@@ -3,83 +3,103 @@
|
||||
#define APU_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "square1/square1.cpp"
|
||||
#include "square2/square2.cpp"
|
||||
#include "wave/wave.cpp"
|
||||
#include "noise/noise.cpp"
|
||||
#include "master/master.cpp"
|
||||
#include "serialization.cpp"
|
||||
APU apu;
|
||||
|
||||
void APU::Main() {
|
||||
apu.main();
|
||||
}
|
||||
|
||||
void APU::main() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(sequencer_base == 0) { //512hz
|
||||
if(sequencer_step == 0 || sequencer_step == 2 || sequencer_step == 4 || sequencer_step == 6) { //256hz
|
||||
square1.clock_length();
|
||||
square2.clock_length();
|
||||
wave.clock_length();
|
||||
noise.clock_length();
|
||||
}
|
||||
if(sequencer_step == 2 || sequencer_step == 6) { //128hz
|
||||
square1.clock_sweep();
|
||||
}
|
||||
if(sequencer_step == 7) { //64hz
|
||||
square1.clock_envelope();
|
||||
square2.clock_envelope();
|
||||
noise.clock_envelope();
|
||||
}
|
||||
sequencer_step++;
|
||||
}
|
||||
sequencer_base++;
|
||||
|
||||
square1.run();
|
||||
square2.run();
|
||||
wave.run();
|
||||
noise.run();
|
||||
master.run();
|
||||
|
||||
system.interface->audio_sample(master.center, master.left, master.right);
|
||||
if(++clock >= 0) co_switch(scheduler.active_thread = cpu.thread);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::power() {
|
||||
create(Main, 4194304);
|
||||
for(unsigned n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
|
||||
|
||||
channel1.sweep_time = 0;
|
||||
channel1.sweep_direction = 0;
|
||||
channel1.sweep_shift = 0;
|
||||
foreach(n, mmio_data) n = 0x00;
|
||||
sequencer_base = 0;
|
||||
sequencer_step = 0;
|
||||
|
||||
channel1.wave_pattern_duty = 0;
|
||||
channel1.sound_length = 0;
|
||||
square1.power();
|
||||
square2.power();
|
||||
wave.power();
|
||||
noise.power();
|
||||
master.power();
|
||||
}
|
||||
|
||||
channel1.initial_envelope_volume = 0;
|
||||
channel1.envelope_direction = 0;
|
||||
channel1.envelope_sweep = 0;
|
||||
uint8 APU::mmio_read(uint16 addr) {
|
||||
static const uint8 table[48] = {
|
||||
0x80, 0x3f, 0x00, 0xff, 0xbf, //square1
|
||||
0xff, 0x3f, 0x00, 0xff, 0xbf, //square2
|
||||
0x7f, 0xff, 0x9f, 0xff, 0xbf, //wave
|
||||
0xff, 0xff, 0x00, 0x00, 0xbf, //noise
|
||||
0x00, 0x00, 0x70, //master
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //unmapped
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
|
||||
};
|
||||
|
||||
channel1.frequency = 0;
|
||||
channel1.initialize = 0;
|
||||
channel1.consecutive_selection = 0;
|
||||
if(addr == 0xff26) {
|
||||
uint8 data = master.enable << 7;
|
||||
if(square1.counter && square1.length) data |= 0x01;
|
||||
if(square2.counter && square2.length) data |= 0x02;
|
||||
if( wave.counter && wave.length) data |= 0x04;
|
||||
if( noise.counter && noise.length) data |= 0x08;
|
||||
return data | table[addr - 0xff10];
|
||||
}
|
||||
|
||||
channel2.wave_pattern_duty = 0;
|
||||
channel2.sound_length = 0;
|
||||
if(addr >= 0xff10 && addr <= 0xff3f) return mmio_data[addr - 0xff10] | table[addr - 0xff10];
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
channel2.initial_envelope_volume = 0;
|
||||
channel2.envelope_direction = 0;
|
||||
channel2.envelope_sweep = 0;
|
||||
void APU::mmio_write(uint16 addr, uint8 data) {
|
||||
if(addr >= 0xff10 && addr <= 0xff3f) mmio_data[addr - 0xff10] = data;
|
||||
|
||||
channel2.frequency = 0;
|
||||
channel2.initialize = 0;
|
||||
channel2.consecutive_selection = 0;
|
||||
|
||||
channel3.off = 0;
|
||||
|
||||
channel3.sound_length = 0;
|
||||
|
||||
channel3.output_level = 0;
|
||||
|
||||
channel3.frequency = 0;
|
||||
channel3.initialize = 0;
|
||||
channel3.consecutive_selection = 0;
|
||||
|
||||
for(unsigned n = 0; n < 16; n++) channel3.pattern[n] = 0;
|
||||
|
||||
channel4.sound_length = 0;
|
||||
|
||||
channel4.initial_envelope_volume = 0;
|
||||
channel4.envelope_direction = 0;
|
||||
channel4.envelope_sweep = 0;
|
||||
|
||||
channel4.shift_clock_frequency = 0;
|
||||
channel4.counter_step_width = 0;
|
||||
channel4.dividing_ratio = 0;
|
||||
|
||||
channel4.initialize = 0;
|
||||
channel4.consecutive_selection = 0;
|
||||
|
||||
control.output_vin_to_so2 = 0;
|
||||
control.so2_output_level = 0;
|
||||
control.output_vin_to_so1 = 0;
|
||||
control.so1_output_level = 0;
|
||||
|
||||
control.output_channel4_to_so2 = 0;
|
||||
control.output_channel3_to_so2 = 0;
|
||||
control.output_channel2_to_so2 = 0;
|
||||
control.output_channel1_to_so2 = 0;
|
||||
control.output_channel4_to_so1 = 0;
|
||||
control.output_channel3_to_so1 = 0;
|
||||
control.output_channel2_to_so1 = 0;
|
||||
control.output_channel1_to_so1 = 0;
|
||||
|
||||
control.sound_on = 0;
|
||||
control.channel4_on = 0;
|
||||
control.channel3_on = 0;
|
||||
control.channel2_on = 0;
|
||||
control.channel1_on = 0;
|
||||
if(addr >= 0xff10 && addr <= 0xff14) return square1.write (addr - 0xff10, data);
|
||||
if(addr >= 0xff15 && addr <= 0xff19) return square2.write (addr - 0xff15, data);
|
||||
if(addr >= 0xff1a && addr <= 0xff1e) return wave.write (addr - 0xff1a, data);
|
||||
if(addr >= 0xff1f && addr <= 0xff23) return noise.write (addr - 0xff1f, data);
|
||||
if(addr >= 0xff24 && addr <= 0xff26) return master.write (addr - 0xff24, data);
|
||||
if(addr >= 0xff30 && addr <= 0xff3f) return wave.write_pattern(addr - 0xff30, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,8 +1,27 @@
|
||||
struct APU : Processor, MMIO {
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "square1/square1.hpp"
|
||||
#include "square2/square2.hpp"
|
||||
#include "wave/wave.hpp"
|
||||
#include "noise/noise.hpp"
|
||||
#include "master/master.hpp"
|
||||
|
||||
uint8 mmio_data[48];
|
||||
uint13 sequencer_base;
|
||||
uint3 sequencer_step;
|
||||
|
||||
Square1 square1;
|
||||
Square2 square2;
|
||||
Wave wave;
|
||||
Noise noise;
|
||||
Master master;
|
||||
|
||||
static void Main();
|
||||
void main();
|
||||
void power();
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
|
132
bsnes/gameboy/apu/master/master.cpp
Executable file
132
bsnes/gameboy/apu/master/master.cpp
Executable file
@@ -0,0 +1,132 @@
|
||||
#ifdef APU_CPP
|
||||
|
||||
void APU::Master::run() {
|
||||
if(enable == false) {
|
||||
center = 0;
|
||||
left = 0;
|
||||
right = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
signed sample = 0, channels;
|
||||
sample += apu.square1.output;
|
||||
sample += apu.square2.output;
|
||||
sample += apu.wave.output;
|
||||
sample += apu.noise.output;
|
||||
sample >>= 2;
|
||||
center = sclamp<16>(sample);
|
||||
|
||||
if(left_enable == false && right_enable == false) {
|
||||
left = center;
|
||||
right = center;
|
||||
return;
|
||||
}
|
||||
|
||||
sample = 0;
|
||||
channels = 0;
|
||||
if(channel1_left_enable) { sample += apu.square1.output; channels++; }
|
||||
if(channel2_left_enable) { sample += apu.square2.output; channels++; }
|
||||
if(channel3_left_enable) { sample += apu.wave.output; channels++; }
|
||||
if(channel4_left_enable) { sample += apu.noise.output; channels++; }
|
||||
if(channels) sample /= channels;
|
||||
left = sclamp<16>(sample);
|
||||
|
||||
switch(left_volume) {
|
||||
case 0: left >>= 3; break; // 12.5%
|
||||
case 1: left >>= 2; break; // 25.0%
|
||||
case 2: left = (left >> 2) + (left >> 3); break; // 37.5%
|
||||
case 3: left >>= 1; break; // 50.0%
|
||||
case 4: left = (left >> 1) + (left >> 3); break; // 62.5%
|
||||
case 5: left -= (left >> 2); break; // 75.0%
|
||||
case 6: left -= (left >> 3); break; // 87.5%
|
||||
//case 7: break; //100.0%
|
||||
}
|
||||
if(left_enable == false) left = 0;
|
||||
|
||||
sample = 0;
|
||||
channels = 0;
|
||||
if(channel1_right_enable) { sample += apu.square1.output; channels++; }
|
||||
if(channel2_right_enable) { sample += apu.square2.output; channels++; }
|
||||
if(channel3_right_enable) { sample += apu.wave.output; channels++; }
|
||||
if(channel4_right_enable) { sample += apu.noise.output; channels++; }
|
||||
if(channels) sample /= channels;
|
||||
right = sclamp<16>(sample);
|
||||
|
||||
switch(right_volume) {
|
||||
case 0: right >>= 3; break; // 12.5%
|
||||
case 1: right >>= 2; break; // 25.0%
|
||||
case 2: right = (right >> 2) + (right >> 3); break; // 37.5%
|
||||
case 3: right >>= 1; break; // 50.0%
|
||||
case 4: right = (right >> 1) + (right >> 3); break; // 62.5%
|
||||
case 5: right -= (right >> 2); break; // 75.0%
|
||||
case 6: right -= (right >> 3); break; // 87.5%
|
||||
//case 7: break; //100.0%
|
||||
}
|
||||
if(right_enable == false) right = 0;
|
||||
}
|
||||
|
||||
void APU::Master::write(unsigned r, uint8 data) {
|
||||
if(r == 0) {
|
||||
left_enable = data & 0x80;
|
||||
left_volume = (data >> 4) & 7;
|
||||
right_enable = data & 0x08;
|
||||
right_volume = (data >> 0) & 7;
|
||||
}
|
||||
|
||||
if(r == 1) {
|
||||
channel4_left_enable = data & 0x80;
|
||||
channel3_left_enable = data & 0x40;
|
||||
channel2_left_enable = data & 0x20;
|
||||
channel1_left_enable = data & 0x10;
|
||||
channel4_right_enable = data & 0x08;
|
||||
channel3_right_enable = data & 0x04;
|
||||
channel2_right_enable = data & 0x02;
|
||||
channel1_right_enable = data & 0x01;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
enable = data & 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Master::power() {
|
||||
left_enable = 0;
|
||||
left_volume = 0;
|
||||
right_enable = 0;
|
||||
right_volume = 0;
|
||||
channel4_left_enable = 0;
|
||||
channel3_left_enable = 0;
|
||||
channel2_left_enable = 0;
|
||||
channel1_left_enable = 0;
|
||||
channel4_right_enable = 0;
|
||||
channel3_right_enable = 0;
|
||||
channel2_right_enable = 0;
|
||||
channel1_right_enable = 0;
|
||||
enable = 0;
|
||||
|
||||
center = 0;
|
||||
left = 0;
|
||||
right = 0;
|
||||
}
|
||||
|
||||
void APU::Master::serialize(serializer &s) {
|
||||
s.integer(left_enable);
|
||||
s.integer(left_volume);
|
||||
s.integer(right_enable);
|
||||
s.integer(right_volume);
|
||||
s.integer(channel4_left_enable);
|
||||
s.integer(channel3_left_enable);
|
||||
s.integer(channel2_left_enable);
|
||||
s.integer(channel1_left_enable);
|
||||
s.integer(channel4_right_enable);
|
||||
s.integer(channel3_right_enable);
|
||||
s.integer(channel2_right_enable);
|
||||
s.integer(channel1_right_enable);
|
||||
s.integer(enable);
|
||||
|
||||
s.integer(center);
|
||||
s.integer(left);
|
||||
s.integer(right);
|
||||
}
|
||||
|
||||
#endif
|
24
bsnes/gameboy/apu/master/master.hpp
Executable file
24
bsnes/gameboy/apu/master/master.hpp
Executable file
@@ -0,0 +1,24 @@
|
||||
struct Master {
|
||||
bool left_enable;
|
||||
unsigned left_volume;
|
||||
bool right_enable;
|
||||
unsigned right_volume;
|
||||
bool channel4_left_enable;
|
||||
bool channel3_left_enable;
|
||||
bool channel2_left_enable;
|
||||
bool channel1_left_enable;
|
||||
bool channel4_right_enable;
|
||||
bool channel3_right_enable;
|
||||
bool channel2_right_enable;
|
||||
bool channel1_right_enable;
|
||||
bool enable;
|
||||
|
||||
int16 center;
|
||||
int16 left;
|
||||
int16 right;
|
||||
|
||||
void run();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
@@ -1,248 +0,0 @@
|
||||
#ifdef APU_CPP
|
||||
|
||||
uint8 APU::mmio_read(uint16 addr) {
|
||||
if(addr == 0xff10) { //NR10
|
||||
return (channel1.sweep_time << 4)
|
||||
| (channel1.sweep_direction << 3)
|
||||
| (channel1.sweep_shift << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff11) { //NR11
|
||||
return (channel1.wave_pattern_duty << 6);
|
||||
}
|
||||
|
||||
if(addr == 0xff12) { //NR12
|
||||
return (channel1.initial_envelope_volume << 4)
|
||||
| (channel1.envelope_direction << 3)
|
||||
| (channel1.envelope_sweep << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff14) { //NR14
|
||||
return (channel1.consecutive_selection << 6);
|
||||
}
|
||||
|
||||
if(addr == 0xff16) { //NR21
|
||||
return (channel2.wave_pattern_duty << 6);
|
||||
}
|
||||
|
||||
if(addr == 0xff17) { //NR22
|
||||
return (channel2.initial_envelope_volume << 4)
|
||||
| (channel2.envelope_direction << 3)
|
||||
| (channel2.envelope_sweep << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff19) { //NR24
|
||||
return (channel2.consecutive_selection << 6);
|
||||
}
|
||||
|
||||
if(addr == 0xff1a) { //NR30
|
||||
return (channel3.off << 7);
|
||||
}
|
||||
|
||||
if(addr == 0xff1b) { //NR31
|
||||
return (channel3.sound_length << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff1c) { //NR32
|
||||
return (channel3.output_level << 5);
|
||||
}
|
||||
|
||||
if(addr == 0xff1e) { //NR34
|
||||
return (channel3.consecutive_selection << 6);
|
||||
}
|
||||
|
||||
if(addr == 0xff20) { //NR41
|
||||
return (channel4.sound_length << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff21) { //NR42
|
||||
return (channel4.initial_envelope_volume << 4)
|
||||
| (channel4.envelope_direction << 3)
|
||||
| (channel4.envelope_sweep << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff22) { //NR43
|
||||
return (channel4.shift_clock_frequency << 4)
|
||||
| (channel4.counter_step_width << 3)
|
||||
| (channel4.dividing_ratio << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff23) { //NR44
|
||||
return (channel4.consecutive_selection << 6);
|
||||
}
|
||||
|
||||
if(addr == 0xff24) { //NR50
|
||||
return (control.output_vin_to_so2 << 7)
|
||||
| (control.so2_output_level << 4)
|
||||
| (control.output_vin_to_so1 << 3)
|
||||
| (control.so1_output_level << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff25) { //NR51
|
||||
return (control.output_channel4_to_so2 << 7)
|
||||
| (control.output_channel3_to_so2 << 6)
|
||||
| (control.output_channel2_to_so2 << 5)
|
||||
| (control.output_channel1_to_so2 << 4)
|
||||
| (control.output_channel4_to_so1 << 3)
|
||||
| (control.output_channel3_to_so1 << 2)
|
||||
| (control.output_channel2_to_so1 << 1)
|
||||
| (control.output_channel1_to_so1 << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff26) { //NR52
|
||||
return (control.sound_on << 7);
|
||||
}
|
||||
|
||||
if(addr >= 0xff30 && addr <= 0xff3f) {
|
||||
return channel3.pattern[addr & 15];
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void APU::mmio_write(uint16 addr, uint8 data) {
|
||||
if(addr == 0xff10) { //NR10
|
||||
channel1.sweep_time = (data >> 4) & 7;
|
||||
channel1.sweep_direction = data & 0x08;
|
||||
channel1.sweep_shift = data & 0x07;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff11) { //NR11
|
||||
channel1.wave_pattern_duty = (data >> 6) & 3;
|
||||
channel1.sound_length = data & 0x3f;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff12) { //NR12
|
||||
channel1.initial_envelope_volume = (data >> 4) & 15;
|
||||
channel1.envelope_direction = data & 0x08;
|
||||
channel1.envelope_sweep = data & 0x07;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff13) { //NR13
|
||||
channel1.frequency = (channel1.frequency & 0x0700) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff14) { //NR14
|
||||
channel1.initialize = data & 0x80;
|
||||
channel1.consecutive_selection = data & 0x40;
|
||||
channel1.frequency = ((data & 7) << 8) | (channel1.frequency & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff16) { //NR21
|
||||
channel2.wave_pattern_duty = (data >> 6) & 3;
|
||||
channel2.sound_length = data & 0x3f;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff17) { //NR22
|
||||
channel2.initial_envelope_volume = (data >> 4) & 15;
|
||||
channel2.envelope_direction = data & 0x08;
|
||||
channel2.envelope_sweep = data & 0x07;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff18) { //NR23
|
||||
channel2.frequency = (channel2.frequency & 0x0700) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff19) { //NR24
|
||||
channel2.initialize = data & 0x80;
|
||||
channel2.consecutive_selection = data & 0x40;
|
||||
channel2.frequency = ((data & 7) << 8) | (channel2.frequency & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff1a) { //NR30
|
||||
channel3.off = data & 0x80;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff1b) { //NR31
|
||||
channel3.sound_length = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff1c) { //NR32
|
||||
channel3.output_level = (data >> 5) & 3;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff1d) { //NR33
|
||||
channel3.frequency = (channel3.frequency & 0x0700) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff1e) { //NR34
|
||||
channel3.initialize = data & 0x80;
|
||||
channel3.consecutive_selection = data & 0x40;
|
||||
channel3.frequency = ((data & 7) << 8) | (channel3.frequency & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff20) { //NR41
|
||||
channel4.sound_length = data & 0x3f;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff21) { //NR42
|
||||
channel4.initial_envelope_volume = (data >> 3) & 15;
|
||||
channel4.envelope_direction = data & 0x08;
|
||||
channel4.envelope_sweep = data & 0x07;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff22) { //NR43
|
||||
channel4.shift_clock_frequency = (data >> 4) & 15;
|
||||
channel4.counter_step_width = data & 0x08;
|
||||
channel4.dividing_ratio = data & 0x07;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff23) { //NR44
|
||||
channel4.initialize = data & 0x80;
|
||||
channel4.consecutive_selection = data & 0x40;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff24) { //NR50
|
||||
control.output_vin_to_so2 = data & 0x80;
|
||||
control.so2_output_level = (data >> 4) & 7;
|
||||
control.output_vin_to_so1 = data & 0x08;
|
||||
control.so1_output_level = (data >> 0) & 7;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff25) { //NR51
|
||||
control.output_channel4_to_so2 = data & 0x80;
|
||||
control.output_channel3_to_so2 = data & 0x40;
|
||||
control.output_channel2_to_so2 = data & 0x20;
|
||||
control.output_channel1_to_so2 = data & 0x10;
|
||||
control.output_channel4_to_so1 = data & 0x08;
|
||||
control.output_channel3_to_so1 = data & 0x04;
|
||||
control.output_channel2_to_so1 = data & 0x02;
|
||||
control.output_channel1_to_so1 = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff26) { //NR52
|
||||
control.sound_on = data & 0x80;
|
||||
control.channel4_on = data & 0x08;
|
||||
control.channel3_on = data & 0x04;
|
||||
control.channel2_on = data & 0x02;
|
||||
control.channel1_on = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0xff30 && addr <= 0xff3f) {
|
||||
channel3.pattern[addr & 15] = data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,102 +0,0 @@
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
struct Channel1 { //tone and sweep
|
||||
//$ff10 NR10
|
||||
unsigned sweep_time;
|
||||
bool sweep_direction;
|
||||
unsigned sweep_shift;
|
||||
|
||||
//$ff11 NR11
|
||||
unsigned wave_pattern_duty;
|
||||
unsigned sound_length;
|
||||
|
||||
//$ff12 NR12
|
||||
unsigned initial_envelope_volume;
|
||||
bool envelope_direction;
|
||||
unsigned envelope_sweep;
|
||||
|
||||
//$ff13,$ff14 NR13,NR14
|
||||
unsigned frequency;
|
||||
bool initialize;
|
||||
bool consecutive_selection;
|
||||
} channel1;
|
||||
|
||||
struct Channel2 { //tone
|
||||
//$ff16 NR21
|
||||
unsigned wave_pattern_duty;
|
||||
unsigned sound_length;
|
||||
|
||||
//$ff17 NR22
|
||||
unsigned initial_envelope_volume;
|
||||
bool envelope_direction;
|
||||
unsigned envelope_sweep;
|
||||
|
||||
//$ff18,$ff19 NR23,NR24
|
||||
unsigned frequency;
|
||||
bool initialize;
|
||||
bool consecutive_selection;
|
||||
} channel2;
|
||||
|
||||
struct Channel3 { //wave output
|
||||
//$ff1a NR30
|
||||
bool off;
|
||||
|
||||
//$ff1b NR31
|
||||
unsigned sound_length;
|
||||
|
||||
//$ff1c NR32
|
||||
unsigned output_level;
|
||||
|
||||
//$ff1d,$ff1e NR33,NR34
|
||||
unsigned frequency;
|
||||
bool initialize;
|
||||
bool consecutive_selection;
|
||||
|
||||
//$ff30-ff3f
|
||||
uint8 pattern[16];
|
||||
} channel3;
|
||||
|
||||
struct Channel4 { //noise
|
||||
//$ff20 NR41
|
||||
unsigned sound_length;
|
||||
|
||||
//$ff21 NR42
|
||||
unsigned initial_envelope_volume;
|
||||
bool envelope_direction;
|
||||
unsigned envelope_sweep;
|
||||
|
||||
//$ff22 NR43
|
||||
unsigned shift_clock_frequency;
|
||||
bool counter_step_width;
|
||||
unsigned dividing_ratio;
|
||||
|
||||
//$ff23 NR44
|
||||
bool initialize;
|
||||
bool consecutive_selection;
|
||||
} channel4;
|
||||
|
||||
struct Control {
|
||||
//$ff24 NR50
|
||||
bool output_vin_to_so2;
|
||||
unsigned so2_output_level;
|
||||
bool output_vin_to_so1;
|
||||
unsigned so1_output_level;
|
||||
|
||||
//$ff25 NR51
|
||||
bool output_channel4_to_so2;
|
||||
bool output_channel3_to_so2;
|
||||
bool output_channel2_to_so2;
|
||||
bool output_channel1_to_so2;
|
||||
bool output_channel4_to_so1;
|
||||
bool output_channel3_to_so1;
|
||||
bool output_channel2_to_so1;
|
||||
bool output_channel1_to_so1;
|
||||
|
||||
//$ff26 NR52
|
||||
bool sound_on;
|
||||
bool channel4_on;
|
||||
bool channel3_on;
|
||||
bool channel2_on;
|
||||
bool channel1_on;
|
||||
} control;
|
102
bsnes/gameboy/apu/noise/noise.cpp
Executable file
102
bsnes/gameboy/apu/noise/noise.cpp
Executable file
@@ -0,0 +1,102 @@
|
||||
#ifdef APU_CPP
|
||||
|
||||
void APU::Noise::run() {
|
||||
if(period && --period == 0) {
|
||||
period = divisor << frequency;
|
||||
if(frequency < 14) {
|
||||
bool bit = (lfsr ^ (lfsr >> 1)) & 1;
|
||||
lfsr = (lfsr >> 1) ^ (bit << 14);
|
||||
if(narrow_lfsr) lfsr |= (bit << 6);
|
||||
}
|
||||
}
|
||||
|
||||
uint4 sample = (lfsr & 1) ? 0 : volume;
|
||||
if(counter && length == 0) sample = 0;
|
||||
|
||||
output = (sample * 4369) - 32768;
|
||||
}
|
||||
|
||||
void APU::Noise::clock_length() {
|
||||
if(counter && length) length--;
|
||||
}
|
||||
|
||||
void APU::Noise::clock_envelope() {
|
||||
if(envelope_period && --envelope_period == 0) {
|
||||
envelope_period = envelope_frequency;
|
||||
if(envelope_direction == 0 && volume > 0) volume--;
|
||||
if(envelope_direction == 1 && volume < 15) volume++;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Noise::write(unsigned r, uint8 data) {
|
||||
if(r == 1) {
|
||||
initial_length = 64 - (data & 0x3f);
|
||||
|
||||
length = initial_length;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
envelope_volume = data >> 4;
|
||||
envelope_direction = data & 0x08;
|
||||
envelope_frequency = data & 0x07;
|
||||
}
|
||||
|
||||
if(r == 3) {
|
||||
frequency = data >> 4;
|
||||
narrow_lfsr = data & 0x08;
|
||||
divisor = (data & 0x07) << 4;
|
||||
if(divisor == 0) divisor = 8;
|
||||
|
||||
period = divisor << frequency;
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
bool initialize = data & 0x80;
|
||||
counter = data & 0x40;
|
||||
|
||||
if(initialize) {
|
||||
lfsr = ~0U;
|
||||
length = initial_length;
|
||||
envelope_period = envelope_frequency;
|
||||
volume = envelope_volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Noise::power() {
|
||||
initial_length = 0;
|
||||
envelope_volume = 0;
|
||||
envelope_direction = 0;
|
||||
envelope_frequency = 0;
|
||||
frequency = 0;
|
||||
narrow_lfsr = 0;
|
||||
divisor = 0;
|
||||
counter = 0;
|
||||
|
||||
output = 0;
|
||||
length = 0;
|
||||
envelope_period = 0;
|
||||
volume = 0;
|
||||
period = 0;
|
||||
lfsr = 0;
|
||||
}
|
||||
|
||||
void APU::Noise::serialize(serializer &s) {
|
||||
s.integer(initial_length);
|
||||
s.integer(envelope_volume);
|
||||
s.integer(envelope_direction);
|
||||
s.integer(envelope_frequency);
|
||||
s.integer(frequency);
|
||||
s.integer(narrow_lfsr);
|
||||
s.integer(divisor);
|
||||
s.integer(counter);
|
||||
|
||||
s.integer(output);
|
||||
s.integer(length);
|
||||
s.integer(envelope_period);
|
||||
s.integer(volume);
|
||||
s.integer(period);
|
||||
s.integer(lfsr);
|
||||
}
|
||||
|
||||
#endif
|
24
bsnes/gameboy/apu/noise/noise.hpp
Executable file
24
bsnes/gameboy/apu/noise/noise.hpp
Executable file
@@ -0,0 +1,24 @@
|
||||
struct Noise {
|
||||
unsigned initial_length;
|
||||
unsigned envelope_volume;
|
||||
bool envelope_direction;
|
||||
unsigned envelope_frequency;
|
||||
unsigned frequency;
|
||||
bool narrow_lfsr;
|
||||
unsigned divisor;
|
||||
bool counter;
|
||||
|
||||
int16 output;
|
||||
unsigned length;
|
||||
unsigned envelope_period;
|
||||
unsigned volume;
|
||||
unsigned period;
|
||||
uint15 lfsr;
|
||||
|
||||
void run();
|
||||
void clock_length();
|
||||
void clock_envelope();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
@@ -1,6 +1,15 @@
|
||||
#ifdef APU_CPP
|
||||
|
||||
void APU::serialize(serializer &s) {
|
||||
s.array(mmio_data);
|
||||
s.integer(sequencer_base);
|
||||
s.integer(sequencer_step);
|
||||
|
||||
square1.serialize(s);
|
||||
square2.serialize(s);
|
||||
wave.serialize(s);
|
||||
noise.serialize(s);
|
||||
master.serialize(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
146
bsnes/gameboy/apu/square1/square1.cpp
Executable file
146
bsnes/gameboy/apu/square1/square1.cpp
Executable file
@@ -0,0 +1,146 @@
|
||||
#ifdef APU_CPP
|
||||
|
||||
void APU::Square1::run() {
|
||||
if(period && --period == 0) {
|
||||
period = 4 * (2048 - frequency);
|
||||
phase = (phase + 1) & 7;
|
||||
switch(duty) {
|
||||
case 0: duty_output = (phase == 6); break; //______-_
|
||||
case 1: duty_output = (phase >= 6); break; //______--
|
||||
case 2: duty_output = (phase >= 4); break; //____----
|
||||
case 3: duty_output = (phase <= 5); break; //------__
|
||||
}
|
||||
}
|
||||
|
||||
uint4 sample = (duty_output ? volume : 0);
|
||||
if(counter && length == 0) sample = 0;
|
||||
|
||||
output = (sample * 4369) - 32768;
|
||||
}
|
||||
|
||||
void APU::Square1::sweep() {
|
||||
if(enable == false) return;
|
||||
|
||||
signed offset = frequency_shadow >> sweep_shift;
|
||||
if(sweep_direction) offset = -offset;
|
||||
frequency_shadow += offset;
|
||||
|
||||
if(frequency_shadow < 0) {
|
||||
frequency_shadow = 0;
|
||||
} else if(frequency_shadow > 2047) {
|
||||
frequency_shadow = 2048;
|
||||
enable = false;
|
||||
}
|
||||
|
||||
if(frequency_shadow <= 2047 && sweep_shift) {
|
||||
frequency = frequency_shadow;
|
||||
period = 4 * (2048 - frequency);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square1::clock_length() {
|
||||
if(counter && length) length--;
|
||||
}
|
||||
|
||||
void APU::Square1::clock_sweep() {
|
||||
if(sweep_frequency && sweep_period && --sweep_period == 0) {
|
||||
sweep_period = sweep_frequency;
|
||||
sweep();
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square1::clock_envelope() {
|
||||
if(envelope_period && --envelope_period == 0) {
|
||||
envelope_period = envelope_frequency;
|
||||
if(envelope_direction == 0 && volume > 0) volume--;
|
||||
if(envelope_direction == 1 && volume < 15) volume++;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square1::write(unsigned r, uint8 data) {
|
||||
if(r == 0) {
|
||||
sweep_frequency = (data >> 4) & 7;
|
||||
sweep_direction = data & 0x08;
|
||||
sweep_shift = data & 0x07;
|
||||
}
|
||||
|
||||
if(r == 1) {
|
||||
duty = data >> 6;
|
||||
length = data & 0x3f;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
envelope_volume = data >> 4;
|
||||
envelope_direction = data & 0x08;
|
||||
envelope_frequency = data & 0x07;
|
||||
}
|
||||
|
||||
if(r == 3) {
|
||||
frequency = (frequency & 0x0700) | data;
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
bool initialize = data & 0x80;
|
||||
counter = data & 0x40;
|
||||
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
||||
|
||||
if(initialize) {
|
||||
envelope_period = envelope_frequency;
|
||||
volume = envelope_volume;
|
||||
frequency_shadow = frequency;
|
||||
sweep_period = sweep_frequency;
|
||||
enable = sweep_period || sweep_shift;
|
||||
if(sweep_shift) sweep();
|
||||
}
|
||||
}
|
||||
|
||||
period = 4 * (2048 - frequency);
|
||||
}
|
||||
|
||||
void APU::Square1::power() {
|
||||
sweep_frequency = 0;
|
||||
sweep_direction = 0;
|
||||
sweep_shift = 0;
|
||||
duty = 0;
|
||||
length = 0;
|
||||
envelope_volume = 0;
|
||||
envelope_direction = 0;
|
||||
envelope_frequency = 0;
|
||||
frequency = 0;
|
||||
counter = 0;
|
||||
|
||||
output = 0;
|
||||
duty_output = 0;
|
||||
phase = 0;
|
||||
period = 0;
|
||||
envelope_period = 0;
|
||||
sweep_period = 0;
|
||||
frequency_shadow = 0;
|
||||
enable = 0;
|
||||
volume = 0;
|
||||
}
|
||||
|
||||
void APU::Square1::serialize(serializer &s) {
|
||||
s.integer(sweep_frequency);
|
||||
s.integer(sweep_direction);
|
||||
s.integer(sweep_shift);
|
||||
s.integer(duty);
|
||||
s.integer(length);
|
||||
s.integer(envelope_volume);
|
||||
s.integer(envelope_direction);
|
||||
s.integer(envelope_frequency);
|
||||
s.integer(frequency);
|
||||
s.integer(counter);
|
||||
|
||||
s.integer(output);
|
||||
s.integer(duty_output);
|
||||
s.integer(phase);
|
||||
s.integer(period);
|
||||
s.integer(envelope_period);
|
||||
s.integer(sweep_period);
|
||||
s.integer(frequency_shadow);
|
||||
s.integer(enable);
|
||||
s.integer(volume);
|
||||
}
|
||||
|
||||
#endif
|
31
bsnes/gameboy/apu/square1/square1.hpp
Executable file
31
bsnes/gameboy/apu/square1/square1.hpp
Executable file
@@ -0,0 +1,31 @@
|
||||
struct Square1 {
|
||||
unsigned sweep_frequency;
|
||||
unsigned sweep_direction;
|
||||
unsigned sweep_shift;
|
||||
unsigned duty;
|
||||
unsigned length;
|
||||
unsigned envelope_volume;
|
||||
unsigned envelope_direction;
|
||||
unsigned envelope_frequency;
|
||||
unsigned frequency;
|
||||
unsigned counter;
|
||||
|
||||
int16 output;
|
||||
bool duty_output;
|
||||
unsigned phase;
|
||||
unsigned period;
|
||||
unsigned envelope_period;
|
||||
unsigned sweep_period;
|
||||
signed frequency_shadow;
|
||||
bool enable;
|
||||
unsigned volume;
|
||||
|
||||
void run();
|
||||
void sweep();
|
||||
void clock_length();
|
||||
void clock_sweep();
|
||||
void clock_envelope();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
97
bsnes/gameboy/apu/square2/square2.cpp
Executable file
97
bsnes/gameboy/apu/square2/square2.cpp
Executable file
@@ -0,0 +1,97 @@
|
||||
#ifdef APU_CPP
|
||||
|
||||
void APU::Square2::run() {
|
||||
if(period && --period == 0) {
|
||||
period = 4 * (2048 - frequency);
|
||||
phase = (phase + 1) & 7;
|
||||
switch(duty) {
|
||||
case 0: duty_output = (phase == 6); break; //______-_
|
||||
case 1: duty_output = (phase >= 6); break; //______--
|
||||
case 2: duty_output = (phase >= 4); break; //____----
|
||||
case 3: duty_output = (phase <= 5); break; //------__
|
||||
}
|
||||
}
|
||||
|
||||
uint4 sample = (duty_output ? volume : 0);
|
||||
if(counter && length == 0) sample = 0;
|
||||
|
||||
output = (sample * 4369) - 32768;
|
||||
}
|
||||
|
||||
void APU::Square2::clock_length() {
|
||||
if(counter && length) length--;
|
||||
}
|
||||
|
||||
void APU::Square2::clock_envelope() {
|
||||
if(envelope_period && --envelope_period == 0) {
|
||||
envelope_period = envelope_frequency;
|
||||
if(envelope_direction == 0 && volume > 0) volume--;
|
||||
if(envelope_direction == 1 && volume < 15) volume++;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square2::write(unsigned r, uint8 data) {
|
||||
if(r == 1) {
|
||||
duty = data >> 6;
|
||||
length = data & 0x3f;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
envelope_volume = data >> 4;
|
||||
envelope_direction = data & 0x08;
|
||||
envelope_frequency = data & 0x07;
|
||||
}
|
||||
|
||||
if(r == 3) {
|
||||
frequency = (frequency & 0x0700) | data;
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
bool initialize = data & 0x80;
|
||||
counter = data & 0x40;
|
||||
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
||||
|
||||
if(initialize) {
|
||||
envelope_period = envelope_frequency;
|
||||
volume = envelope_volume;
|
||||
}
|
||||
}
|
||||
|
||||
period = 4 * (2048 - frequency);
|
||||
}
|
||||
|
||||
void APU::Square2::power() {
|
||||
duty = 0;
|
||||
length = 0;
|
||||
envelope_volume = 0;
|
||||
envelope_direction = 0;
|
||||
envelope_frequency = 0;
|
||||
frequency = 0;
|
||||
counter = 0;
|
||||
|
||||
output = 0;
|
||||
duty_output = 0;
|
||||
phase = 0;
|
||||
period = 0;
|
||||
envelope_period = 0;
|
||||
volume = 0;
|
||||
}
|
||||
|
||||
void APU::Square2::serialize(serializer &s) {
|
||||
s.integer(duty);
|
||||
s.integer(length);
|
||||
s.integer(envelope_volume);
|
||||
s.integer(envelope_direction);
|
||||
s.integer(envelope_frequency);
|
||||
s.integer(frequency);
|
||||
s.integer(counter);
|
||||
|
||||
s.integer(output);
|
||||
s.integer(duty_output);
|
||||
s.integer(phase);
|
||||
s.integer(period);
|
||||
s.integer(envelope_period);
|
||||
s.integer(volume);
|
||||
}
|
||||
|
||||
#endif
|
23
bsnes/gameboy/apu/square2/square2.hpp
Executable file
23
bsnes/gameboy/apu/square2/square2.hpp
Executable file
@@ -0,0 +1,23 @@
|
||||
struct Square2 {
|
||||
unsigned duty;
|
||||
unsigned length;
|
||||
unsigned envelope_volume;
|
||||
unsigned envelope_direction;
|
||||
unsigned envelope_frequency;
|
||||
unsigned frequency;
|
||||
unsigned counter;
|
||||
|
||||
int16 output;
|
||||
bool duty_output;
|
||||
unsigned phase;
|
||||
unsigned period;
|
||||
unsigned envelope_period;
|
||||
unsigned volume;
|
||||
|
||||
void run();
|
||||
void clock_length();
|
||||
void clock_envelope();
|
||||
void write(unsigned r, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
103
bsnes/gameboy/apu/wave/wave.cpp
Executable file
103
bsnes/gameboy/apu/wave/wave.cpp
Executable file
@@ -0,0 +1,103 @@
|
||||
#ifdef APU_CPP
|
||||
|
||||
void APU::Wave::run() {
|
||||
if(period && --period == 0) {
|
||||
period = 2 * (2048 - frequency);
|
||||
pattern_offset = (pattern_offset + 1) & 31;
|
||||
pattern_sample = pattern[pattern_offset];
|
||||
}
|
||||
|
||||
uint4 sample = pattern_sample;
|
||||
if(counter && length == 0) sample = 0;
|
||||
if(enable == false) sample = 0;
|
||||
|
||||
output = (sample * 4369) - 32768;
|
||||
output >>= volume;
|
||||
}
|
||||
|
||||
void APU::Wave::clock_length() {
|
||||
if(counter && length) length--;
|
||||
}
|
||||
|
||||
void APU::Wave::write(unsigned r, uint8 data) {
|
||||
if(r == 0) {
|
||||
dac_enable = data & 0x80;
|
||||
|
||||
if(dac_enable == false) enable = false;
|
||||
}
|
||||
|
||||
if(r == 1) {
|
||||
initial_length = 256 - data;
|
||||
|
||||
length = initial_length;
|
||||
}
|
||||
|
||||
if(r == 2) {
|
||||
switch((data >> 5) & 3) {
|
||||
case 0: volume = 16; break; // 0%
|
||||
case 1: volume = 0; break; //100%
|
||||
case 2: volume = 1; break; // 50%
|
||||
case 3: volume = 2; break; // 25%
|
||||
}
|
||||
}
|
||||
|
||||
if(r == 3) {
|
||||
frequency = (frequency & 0x0700) | data;
|
||||
}
|
||||
|
||||
if(r == 4) {
|
||||
bool initialize = data & 0x80;
|
||||
counter = data & 0x40;
|
||||
frequency = ((data & 7) << 8) | (frequency & 0x00ff);
|
||||
|
||||
if(initialize && dac_enable) {
|
||||
enable = true;
|
||||
pattern_offset = 0;
|
||||
length = initial_length;
|
||||
}
|
||||
}
|
||||
|
||||
period = 2 * (2048 - frequency);
|
||||
}
|
||||
|
||||
void APU::Wave::write_pattern(unsigned p, uint8 data) {
|
||||
p <<= 1;
|
||||
pattern[p + 0] = (data >> 4) & 15;
|
||||
pattern[p + 1] = (data >> 0) & 15;
|
||||
}
|
||||
|
||||
void APU::Wave::power() {
|
||||
dac_enable = 0;
|
||||
initial_length = 0;
|
||||
volume = 0;
|
||||
frequency = 0;
|
||||
counter = 0;
|
||||
|
||||
random_lfsr r;
|
||||
foreach(n, pattern) n = r() & 15;
|
||||
|
||||
output = 0;
|
||||
enable = 0;
|
||||
length = 0;
|
||||
period = 0;
|
||||
pattern_offset = 0;
|
||||
pattern_sample = 0;
|
||||
}
|
||||
|
||||
void APU::Wave::serialize(serializer &s) {
|
||||
s.integer(dac_enable);
|
||||
s.integer(initial_length);
|
||||
s.integer(volume);
|
||||
s.integer(frequency);
|
||||
s.integer(counter);
|
||||
s.array(pattern);
|
||||
|
||||
s.integer(output);
|
||||
s.integer(enable);
|
||||
s.integer(length);
|
||||
s.integer(period);
|
||||
s.integer(pattern_offset);
|
||||
s.integer(pattern_sample);
|
||||
}
|
||||
|
||||
#endif
|
22
bsnes/gameboy/apu/wave/wave.hpp
Executable file
22
bsnes/gameboy/apu/wave/wave.hpp
Executable file
@@ -0,0 +1,22 @@
|
||||
struct Wave {
|
||||
bool dac_enable;
|
||||
unsigned initial_length;
|
||||
unsigned volume;
|
||||
unsigned frequency;
|
||||
bool counter;
|
||||
uint8 pattern[32];
|
||||
|
||||
int16 output;
|
||||
bool enable;
|
||||
unsigned length;
|
||||
unsigned period;
|
||||
unsigned pattern_offset;
|
||||
unsigned pattern_sample;
|
||||
|
||||
void run();
|
||||
void clock_length();
|
||||
void write(unsigned r, uint8 data);
|
||||
void write_pattern(unsigned p, uint8 data);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
@@ -70,7 +70,19 @@ void Cartridge::load(const string &xml, const uint8_t *data, unsigned size) {
|
||||
}
|
||||
}
|
||||
|
||||
switch(info.mapper) { default:
|
||||
case Mapper::MBC0: mapper = &mbc0; break;
|
||||
case Mapper::MBC1: mapper = &mbc1; break;
|
||||
case Mapper::MBC2: mapper = &mbc2; break;
|
||||
case Mapper::MBC3: mapper = &mbc3; break;
|
||||
case Mapper::MBC5: mapper = &mbc5; break;
|
||||
case Mapper::MMM01: mapper = &mmm01; break;
|
||||
case Mapper::HuC1: mapper = &huc1; break;
|
||||
case Mapper::HuC3: mapper = &huc3; break;
|
||||
}
|
||||
|
||||
ramdata = new uint8_t[ramsize = info.ramsize]();
|
||||
system.load();
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
@@ -104,7 +116,19 @@ void Cartridge::ram_write(unsigned addr, uint8 data) {
|
||||
ramdata[addr] = data;
|
||||
}
|
||||
|
||||
uint8 Cartridge::mmio_read(uint16 addr) {
|
||||
if(bootrom_enable && within<0x0000, 0x00ff>(addr)) return System::BootROM::sgb[addr];
|
||||
return mapper->mmio_read(addr);
|
||||
}
|
||||
|
||||
void Cartridge::mmio_write(uint16 addr, uint8 data) {
|
||||
if(bootrom_enable && addr == 0xff50) bootrom_enable = false;
|
||||
mapper->mmio_write(addr, data);
|
||||
}
|
||||
|
||||
void Cartridge::power() {
|
||||
bootrom_enable = true;
|
||||
|
||||
mbc0.power();
|
||||
mbc1.power();
|
||||
mbc2.power();
|
||||
@@ -113,26 +137,10 @@ void Cartridge::power() {
|
||||
mmm01.power();
|
||||
huc1.power();
|
||||
huc3.power();
|
||||
map();
|
||||
}
|
||||
|
||||
void Cartridge::map() {
|
||||
MMIO *mapper = 0;
|
||||
switch(info.mapper) { default:
|
||||
case Mapper::MBC0: mapper = &mbc0; break;
|
||||
case Mapper::MBC1: mapper = &mbc1; break;
|
||||
case Mapper::MBC2: mapper = &mbc2; break;
|
||||
case Mapper::MBC3: mapper = &mbc3; break;
|
||||
case Mapper::MBC5: mapper = &mbc5; break;
|
||||
case Mapper::MMM01: mapper = &mmm01; break;
|
||||
case Mapper::HuC1: mapper = &huc1; break;
|
||||
case Mapper::HuC3: mapper = &huc3; break;
|
||||
}
|
||||
|
||||
if(mapper) {
|
||||
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = mapper;
|
||||
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = mapper;
|
||||
}
|
||||
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this;
|
||||
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this;
|
||||
bus.mmio[0xff50] = this;
|
||||
}
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
struct Cartridge : property<Cartridge> {
|
||||
struct Cartridge : MMIO, property<Cartridge> {
|
||||
#include "mbc0/mbc0.hpp"
|
||||
#include "mbc1/mbc1.hpp"
|
||||
#include "mbc2/mbc2.hpp"
|
||||
@@ -41,6 +41,9 @@ struct Cartridge : property<Cartridge> {
|
||||
uint8_t *ramdata;
|
||||
unsigned ramsize;
|
||||
|
||||
MMIO *mapper;
|
||||
bool bootrom_enable;
|
||||
|
||||
void load(const string &xml, const uint8_t *data, unsigned size);
|
||||
void unload();
|
||||
|
||||
@@ -49,8 +52,10 @@ struct Cartridge : property<Cartridge> {
|
||||
uint8 ram_read(unsigned addr);
|
||||
void ram_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void map();
|
||||
|
||||
void serialize(serializer&);
|
||||
Cartridge();
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
if(info.battery) s.array(ramdata, ramsize);
|
||||
s.integer(bootrom_enable);
|
||||
|
||||
s.integer(mbc1.ram_enable);
|
||||
s.integer(mbc1.rom_select);
|
||||
|
@@ -94,7 +94,7 @@ void CPU::interrupt_exec(uint16 pc) {
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
create(Main, 4 * 1024 * 1024);
|
||||
create(Main, 4194304);
|
||||
|
||||
for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM
|
||||
for(unsigned n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror)
|
||||
@@ -114,13 +114,7 @@ void CPU::power() {
|
||||
status.clock = 0;
|
||||
status.halt = false;
|
||||
status.stop = false;
|
||||
|
||||
status.ime = 0;
|
||||
status.timer0 = 0;
|
||||
status.timer1 = 0;
|
||||
status.timer2 = 0;
|
||||
status.timer3 = 0;
|
||||
status.timer4 = 0;
|
||||
|
||||
status.p15 = 0;
|
||||
status.p14 = 0;
|
||||
|
@@ -17,13 +17,7 @@ struct CPU : Processor, MMIO {
|
||||
unsigned clock;
|
||||
bool halt;
|
||||
bool stop;
|
||||
|
||||
bool ime;
|
||||
unsigned timer0;
|
||||
unsigned timer1;
|
||||
unsigned timer2;
|
||||
unsigned timer3;
|
||||
unsigned timer4;
|
||||
|
||||
//$ff00 JOYP
|
||||
bool p15;
|
||||
|
@@ -21,13 +21,7 @@ void CPU::serialize(serializer &s) {
|
||||
s.integer(status.clock);
|
||||
s.integer(status.halt);
|
||||
s.integer(status.stop);
|
||||
|
||||
s.integer(status.ime);
|
||||
s.integer(status.timer0);
|
||||
s.integer(status.timer1);
|
||||
s.integer(status.timer2);
|
||||
s.integer(status.timer3);
|
||||
s.integer(status.timer4);
|
||||
|
||||
s.integer(status.p15);
|
||||
s.integer(status.p14);
|
||||
|
@@ -1,13 +1,9 @@
|
||||
//4194304hz (4 * 1024 * 1024)
|
||||
|
||||
//70224 clocks/frame
|
||||
// 456 clocks/scanline
|
||||
// 154 scanlines/frame
|
||||
|
||||
//4194304 / 4096 = 1024
|
||||
//4194304 / 262144 = 16
|
||||
//4194304 / 65536 = 64
|
||||
//4394304 / 16384 = 256
|
||||
|
||||
#ifdef CPU_CPP
|
||||
|
||||
#include "opcode.cpp"
|
||||
@@ -17,43 +13,44 @@ void CPU::add_clocks(unsigned clocks) {
|
||||
scheduler.exit(Scheduler::ExitReason::StepEvent);
|
||||
|
||||
status.clock += clocks;
|
||||
if(status.clock >= 4 * 1024 * 1024) {
|
||||
status.clock -= 4 * 1024 * 1024;
|
||||
if(status.clock >= 4194304) {
|
||||
status.clock -= 4194304;
|
||||
cartridge.mbc3.second();
|
||||
}
|
||||
|
||||
status.timer0 += clocks;
|
||||
if(status.timer0 >= 16) timer_stage0();
|
||||
//4194304 / N(hz) - 1 = mask
|
||||
if((status.clock & 15) == 0) timer_262144hz();
|
||||
if((status.clock & 63) == 0) timer_65536hz();
|
||||
if((status.clock & 255) == 0) timer_16384hz();
|
||||
if((status.clock & 511) == 0) timer_8192hz();
|
||||
if((status.clock & 1023) == 0) timer_4096hz();
|
||||
|
||||
cpu.clock += clocks;
|
||||
if(cpu.clock >= 0) co_switch(scheduler.active_thread = lcd.thread);
|
||||
lcd.clock -= clocks;
|
||||
if(lcd.clock <= 0) co_switch(scheduler.active_thread = lcd.thread);
|
||||
|
||||
apu.clock -= clocks;
|
||||
if(apu.clock <= 0) co_switch(scheduler.active_thread = apu.thread);
|
||||
}
|
||||
|
||||
void CPU::timer_stage0() { //262144hz
|
||||
void CPU::timer_262144hz() {
|
||||
if(status.timer_enable && status.timer_clock == 1) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
interrupt_raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
|
||||
status.timer0 -= 16;
|
||||
if(++status.timer1 >= 4) timer_stage1();
|
||||
}
|
||||
|
||||
void CPU::timer_stage1() { // 65536hz
|
||||
void CPU::timer_65536hz() {
|
||||
if(status.timer_enable && status.timer_clock == 2) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
interrupt_raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
|
||||
status.timer1 -= 4;
|
||||
if(++status.timer2 >= 4) timer_stage2();
|
||||
}
|
||||
|
||||
void CPU::timer_stage2() { // 16384hz
|
||||
void CPU::timer_16384hz() {
|
||||
if(status.timer_enable && status.timer_clock == 3) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
@@ -62,32 +59,24 @@ void CPU::timer_stage2() { // 16384hz
|
||||
}
|
||||
|
||||
status.div++;
|
||||
|
||||
status.timer2 -= 4;
|
||||
if(++status.timer3 >= 2) timer_stage3();
|
||||
}
|
||||
|
||||
void CPU::timer_stage3() { // 8192hz
|
||||
void CPU::timer_8192hz() {
|
||||
if(status.serial_transfer && status.serial_clock) {
|
||||
if(--status.serial_bits == 0) {
|
||||
status.serial_transfer = 0;
|
||||
interrupt_raise(Interrupt::Serial);
|
||||
}
|
||||
}
|
||||
|
||||
status.timer3 -= 2;
|
||||
if(++status.timer4 >= 2) timer_stage4();
|
||||
}
|
||||
|
||||
void CPU::timer_stage4() { // 4096hz
|
||||
void CPU::timer_4096hz() {
|
||||
if(status.timer_enable && status.timer_clock == 0) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
interrupt_raise(Interrupt::Timer);
|
||||
}
|
||||
}
|
||||
|
||||
status.timer4 -= 2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,9 +1,9 @@
|
||||
void add_clocks(unsigned clocks);
|
||||
void timer_stage0();
|
||||
void timer_stage1();
|
||||
void timer_stage2();
|
||||
void timer_stage3();
|
||||
void timer_stage4();
|
||||
void timer_262144hz();
|
||||
void timer_65536hz();
|
||||
void timer_16384hz();
|
||||
void timer_8192hz();
|
||||
void timer_4096hz();
|
||||
|
||||
//opcode.cpp
|
||||
void op_io();
|
||||
|
@@ -5,7 +5,7 @@
|
||||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgameboy";
|
||||
static const char Version[] = "000.13";
|
||||
static const char Version[] = "000.19";
|
||||
static unsigned SerializerVersion = 1;
|
||||
}
|
||||
}
|
||||
@@ -15,22 +15,56 @@ namespace GameBoy {
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/property.hpp>
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
using namespace nall;
|
||||
|
||||
namespace GameBoy {
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
typedef uint_t< 1> uint1;
|
||||
typedef uint_t< 2> uint2;
|
||||
typedef uint_t< 3> uint3;
|
||||
typedef uint_t< 4> uint4;
|
||||
typedef uint_t< 5> uint5;
|
||||
typedef uint_t< 6> uint6;
|
||||
typedef uint_t< 7> uint7;
|
||||
|
||||
typedef uint_t< 9> uint9;
|
||||
typedef uint_t<10> uint10;
|
||||
typedef uint_t<11> uint11;
|
||||
typedef uint_t<12> uint12;
|
||||
typedef uint_t<13> uint13;
|
||||
typedef uint_t<14> uint14;
|
||||
typedef uint_t<15> uint15;
|
||||
|
||||
typedef uint_t<17> uint17;
|
||||
typedef uint_t<18> uint18;
|
||||
typedef uint_t<19> uint19;
|
||||
typedef uint_t<20> uint20;
|
||||
typedef uint_t<21> uint21;
|
||||
typedef uint_t<22> uint22;
|
||||
typedef uint_t<23> uint23;
|
||||
typedef uint_t<24> uint24;
|
||||
typedef uint_t<25> uint25;
|
||||
typedef uint_t<26> uint26;
|
||||
typedef uint_t<27> uint27;
|
||||
typedef uint_t<28> uint28;
|
||||
typedef uint_t<29> uint29;
|
||||
typedef uint_t<30> uint30;
|
||||
typedef uint_t<31> uint31;
|
||||
|
||||
template<uint16 lo, uint16 hi>
|
||||
alwaysinline bool within(uint16 addr) {
|
||||
static const uint16 mask = ~(hi ^ lo);
|
||||
|
@@ -1,9 +1,10 @@
|
||||
class Interface {
|
||||
public:
|
||||
virtual void lcd_scanline() {}
|
||||
virtual void joyp_write(bool p15, bool p14) {}
|
||||
|
||||
virtual void video_refresh(const uint8_t *data) {}
|
||||
virtual void audio_sample(signed left, signed right) {}
|
||||
virtual void audio_sample(int16_t center, int16_t left, int16_t right) {}
|
||||
virtual void input_poll() {}
|
||||
virtual bool input_poll(unsigned id) {}
|
||||
|
||||
|
@@ -33,8 +33,8 @@ void LCD::add_clocks(unsigned clocks) {
|
||||
status.lx += clocks;
|
||||
if(status.lx >= 456) scanline();
|
||||
|
||||
cpu.clock -= clocks;
|
||||
if(cpu.clock <= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
clock += clocks;
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
co_switch(scheduler.active_thread = cpu.thread);
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@ void LCD::render() {
|
||||
|
||||
uint8_t *output = screen + status.ly * 160;
|
||||
for(unsigned n = 0; n < 160; n++) output[n] = (3 - line[n]) * 0x55;
|
||||
system.interface->lcd_scanline();
|
||||
}
|
||||
|
||||
uint16 LCD::read_tile(bool select, unsigned x, unsigned y) {
|
||||
@@ -190,7 +191,7 @@ void LCD::render_obj() {
|
||||
}
|
||||
|
||||
void LCD::power() {
|
||||
create(Main, 4 * 1024 * 1024);
|
||||
create(Main, 4194304);
|
||||
|
||||
for(unsigned n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM
|
||||
for(unsigned n = 0xff40; n <= 0xff4b; n++) bus.mmio[n] = this; //MMIO
|
||||
|
@@ -50,7 +50,7 @@ void Bus::write(uint16 addr, uint8 data) {
|
||||
}
|
||||
|
||||
void Bus::power() {
|
||||
for(unsigned n = 0; n < 65536; n++) mmio[n] = &unmapped;
|
||||
for(unsigned n = 0x0000; n <= 0xffff; n++) mmio[n] = &unmapped;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -33,23 +33,14 @@ void System::runthreadtosave() {
|
||||
}
|
||||
}
|
||||
|
||||
uint8 System::mmio_read(uint16 addr) {
|
||||
if((addr & 0xff00) == 0x0000) {
|
||||
return BootROM::sgb[addr];
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void System::mmio_write(uint16 addr, uint8 data) {
|
||||
if(addr == 0xff50) {
|
||||
if(data == 0x01) cartridge.map();
|
||||
}
|
||||
}
|
||||
|
||||
void System::init(Interface *interface_) {
|
||||
interface = interface_;
|
||||
}
|
||||
|
||||
void System::load() {
|
||||
serialize_init();
|
||||
}
|
||||
|
||||
void System::power() {
|
||||
bus.power();
|
||||
cartridge.power();
|
||||
@@ -58,11 +49,7 @@ void System::power() {
|
||||
lcd.power();
|
||||
scheduler.init();
|
||||
|
||||
for(unsigned n = 0x0000; n <= 0x00ff; n++) bus.mmio[n] = this;
|
||||
bus.mmio[0xff50] = this;
|
||||
|
||||
clocks_executed = 0;
|
||||
serialize_init();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ enum class Input : unsigned {
|
||||
Up, Down, Left, Right, B, A, Select, Start,
|
||||
};
|
||||
|
||||
struct System : MMIO {
|
||||
struct System {
|
||||
struct BootROM {
|
||||
static const uint8 dmg[256];
|
||||
static const uint8 sgb[256];
|
||||
@@ -14,10 +14,8 @@ struct System : MMIO {
|
||||
void runtosave();
|
||||
void runthreadtosave();
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void init(Interface*);
|
||||
void load();
|
||||
void power();
|
||||
|
||||
Interface *interface;
|
||||
|
@@ -54,6 +54,10 @@ namespace nall {
|
||||
operator[](buffersize) = data;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
if(size > 0) resize(size - 1); //remove last element only
|
||||
}
|
||||
|
||||
template<typename U> void insert(unsigned index, const U list) {
|
||||
unsigned listsize = container_size(list);
|
||||
resize(buffersize + listsize);
|
||||
@@ -133,6 +137,12 @@ namespace nall {
|
||||
if(index >= buffersize) throw "array[] out of bounds";
|
||||
return pool[index];
|
||||
}
|
||||
|
||||
//iteration
|
||||
T* begin() { return &pool[0]; }
|
||||
T* end() { return &pool[buffersize]; }
|
||||
const T* begin() const { return &pool[0]; }
|
||||
const T* end() const { return &pool[buffersize]; }
|
||||
};
|
||||
|
||||
template<typename T> struct has_size<array<T>> { enum { value = true }; };
|
||||
|
@@ -72,6 +72,7 @@ namespace nall {
|
||||
|
||||
private:
|
||||
static char enc(uint8_t n) {
|
||||
//base64 for URL encodings
|
||||
static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
return lookup_table[n & 63];
|
||||
}
|
||||
|
101
bsnes/nall/bmp.hpp
Executable file
101
bsnes/nall/bmp.hpp
Executable file
@@ -0,0 +1,101 @@
|
||||
#ifndef NALL_BMP_HPP
|
||||
#define NALL_BMP_HPP
|
||||
|
||||
#include <nall/file.hpp>
|
||||
|
||||
//BMP reader / writer
|
||||
//author: byuu
|
||||
//note: only 24-bit RGB and 32-bit ARGB uncompressed images supported
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct bmp {
|
||||
inline static bool read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height);
|
||||
inline static bool write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha = false);
|
||||
};
|
||||
|
||||
bool bmp::read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height) {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode::read) == false) return false;
|
||||
if(fp.size() < 0x36) return false;
|
||||
|
||||
if(fp.readm(2) != 0x424d) return false;
|
||||
fp.seek(0x000a);
|
||||
unsigned offset = fp.readl(4);
|
||||
unsigned dibsize = fp.readl(4);
|
||||
if(dibsize != 40) return false;
|
||||
signed headerWidth = fp.readl(4);
|
||||
if(headerWidth < 0) return false;
|
||||
signed headerHeight = fp.readl(4);
|
||||
fp.readl(2);
|
||||
unsigned bitsPerPixel = fp.readl(2);
|
||||
if(bitsPerPixel != 24 && bitsPerPixel != 32) return false;
|
||||
unsigned compression = fp.readl(4);
|
||||
if(compression != 0) return false;
|
||||
fp.seek(offset);
|
||||
|
||||
bool noFlip = headerHeight < 0;
|
||||
width = headerWidth, height = abs(headerHeight);
|
||||
data = new uint32_t[width * height];
|
||||
|
||||
unsigned bytesPerPixel = bitsPerPixel / 8;
|
||||
unsigned alignedWidth = width * bytesPerPixel;
|
||||
unsigned paddingLength = 0;
|
||||
while(alignedWidth % 4) alignedWidth++, paddingLength++;
|
||||
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
uint32_t *p = noFlip ? data + y * width : data + (height - 1 - y) * width;
|
||||
for(unsigned x = 0; x < width; x++, p++) {
|
||||
*p = fp.readl(bytesPerPixel);
|
||||
if(bytesPerPixel == 3) *p |= 255 << 24;
|
||||
}
|
||||
if(paddingLength) fp.readl(paddingLength);
|
||||
}
|
||||
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp::write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha) {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode::write) == false) return false;
|
||||
|
||||
unsigned bitsPerPixel = alpha ? 32 : 24;
|
||||
unsigned bytesPerPixel = bitsPerPixel / 8;
|
||||
unsigned alignedWidth = width * bytesPerPixel;
|
||||
unsigned paddingLength = 0;
|
||||
unsigned imageSize = alignedWidth * height;
|
||||
unsigned fileSize = 0x36 + imageSize;
|
||||
while(alignedWidth % 4) alignedWidth++, paddingLength++;
|
||||
|
||||
fp.writem(0x424d, 2); //signature
|
||||
fp.writel(fileSize, 4); //file size
|
||||
fp.writel(0, 2); //reserved
|
||||
fp.writel(0, 2); //reserved
|
||||
fp.writel(0x36, 4); //offset
|
||||
|
||||
fp.writel(40, 4); //DIB size
|
||||
fp.writel(width, 4); //width
|
||||
fp.writel(-height, 4); //height
|
||||
fp.writel(1, 2); //color planes
|
||||
fp.writel(bitsPerPixel, 2); //bits per pixel
|
||||
fp.writel(0, 4); //compression method (BI_RGB)
|
||||
fp.writel(imageSize, 4); //image data size
|
||||
fp.writel(3780, 4); //horizontal resolution
|
||||
fp.writel(3780, 4); //vertical resolution
|
||||
fp.writel(0, 4); //palette size
|
||||
fp.writel(0, 4); //important color count
|
||||
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
const uint32_t *p = (const uint32_t*)((const uint8_t*)data + y * pitch);
|
||||
for(unsigned x = 0; x < width; x++) fp.writel(*p++, bytesPerPixel);
|
||||
if(paddingLength) fp.writel(0, paddingLength);
|
||||
}
|
||||
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
79
bsnes/nall/compositor.hpp
Executable file
79
bsnes/nall/compositor.hpp
Executable file
@@ -0,0 +1,79 @@
|
||||
#ifndef NALL_COMPOSITOR_HPP
|
||||
#define NALL_COMPOSITOR_HPP
|
||||
|
||||
#include <nall/detect.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct compositor {
|
||||
inline static bool enabled();
|
||||
inline static bool enable(bool status);
|
||||
};
|
||||
|
||||
#if defined(PLATFORM_X)
|
||||
|
||||
bool compositor::enabled() {
|
||||
FILE *fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r");
|
||||
if(fp == 0) return false;
|
||||
|
||||
char buffer[512];
|
||||
if(fgets(buffer, sizeof buffer, fp) == 0) return false;
|
||||
|
||||
if(!memcmp(buffer, "true", 4)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool compositor::enable(bool status) {
|
||||
FILE *fp;
|
||||
if(status) {
|
||||
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r");
|
||||
} else {
|
||||
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'false'", "r");
|
||||
}
|
||||
if(fp == 0) return false;
|
||||
pclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif defined(PLATFORM_WIN)
|
||||
|
||||
bool compositor::enabled() {
|
||||
HMODULE module = GetModuleHandleW(L"dwmapi");
|
||||
if(module == 0) module = LoadLibraryW(L"dwmapi");
|
||||
if(module == 0) return false;
|
||||
|
||||
auto pDwmIsCompositionEnabled = (HRESULT (WINAPI*)(BOOL*))GetProcAddress(module, "DwmIsCompositionEnabled");
|
||||
if(pDwmIsCompositionEnabled == 0) return false;
|
||||
|
||||
BOOL result;
|
||||
if(pDwmIsCompositionEnabled(&result) != S_OK) return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool compositor::enable(bool status) {
|
||||
HMODULE module = GetModuleHandleW(L"dwmapi");
|
||||
if(module == 0) module = LoadLibraryW(L"dwmapi");
|
||||
if(module == 0) return false;
|
||||
|
||||
auto pDwmEnableComposition = (HRESULT (WINAPI*)(UINT))GetProcAddress(module, "DwmEnableComposition");
|
||||
if(pDwmEnableComposition == 0) return false;
|
||||
|
||||
if(pDwmEnableComposition(status) != S_OK) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool compositor::enabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool compositor::enable(bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -34,11 +34,11 @@ namespace nall {
|
||||
|
||||
string get() const {
|
||||
switch(type) {
|
||||
case boolean_t: return string() << *(bool*)data;
|
||||
case signed_t: return string() << *(signed*)data;
|
||||
case unsigned_t: return string() << *(unsigned*)data;
|
||||
case double_t: return string() << *(double*)data;
|
||||
case string_t: return string() << "\"" << *(string*)data << "\"";
|
||||
case boolean_t: return { *(bool*)data };
|
||||
case signed_t: return { *(signed*)data };
|
||||
case unsigned_t: return { *(unsigned*)data };
|
||||
case double_t: return { *(double*)data };
|
||||
case string_t: return { "\"", *(string*)data, "\"" };
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
@@ -105,9 +105,9 @@ namespace nall {
|
||||
if(fp.open(filename, file::mode::write)) {
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
string output;
|
||||
output << list[i].name << " = " << list[i].get();
|
||||
if(list[i].desc != "") output << " # " << list[i].desc;
|
||||
output << "\r\n";
|
||||
output.append(list[i].name, " = ", list[i].get());
|
||||
if(list[i].desc != "") output.append(" # ", list[i].desc);
|
||||
output.append("\r\n");
|
||||
fp.print(output);
|
||||
}
|
||||
|
||||
|
@@ -1,75 +0,0 @@
|
||||
#ifndef NALL_DICTIONARY_HPP
|
||||
#define NALL_DICTIONARY_HPP
|
||||
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
namespace nall {
|
||||
class dictionary {
|
||||
public:
|
||||
string operator[](const char *input) {
|
||||
for(unsigned i = 0; i < index_input.size(); i++) {
|
||||
if(index_input[i] == input) return index_output[i];
|
||||
}
|
||||
|
||||
//no match, use input; remove input identifier, if one exists
|
||||
if(strbegin(input, "{{")) {
|
||||
if(auto pos = strpos(input, "}}")) {
|
||||
string temp = substr(input, pos() + 2);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
bool import(const char *filename) {
|
||||
string data;
|
||||
if(data.readfile(filename) == false) return false;
|
||||
data.ltrim<1>("\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
|
||||
data.replace("\r", "");
|
||||
|
||||
lstring line;
|
||||
line.split("\n", data);
|
||||
for(unsigned i = 0; i < line.size(); i++) {
|
||||
lstring part;
|
||||
//format: "Input" = "Output"
|
||||
part.qsplit("=", line[i]);
|
||||
if(part.size() != 2) continue;
|
||||
|
||||
//remove whitespace
|
||||
part[0].trim();
|
||||
part[1].trim();
|
||||
|
||||
//remove quotes
|
||||
part[0].trim<1>("\"");
|
||||
part[1].trim<1>("\"");
|
||||
|
||||
unsigned n = index_input.size();
|
||||
index_input[n] = part[0];
|
||||
index_output[n] = part[1];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
index_input.reset();
|
||||
index_output.reset();
|
||||
}
|
||||
|
||||
~dictionary() {
|
||||
reset();
|
||||
}
|
||||
|
||||
dictionary& operator=(const dictionary&) = delete;
|
||||
dictionary(const dictionary&) = delete;
|
||||
|
||||
protected:
|
||||
lstring index_input;
|
||||
lstring index_output;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@@ -6,7 +6,7 @@
|
||||
#include <nall/string.hpp>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/windows/utf8.hpp>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
@@ -41,21 +41,22 @@ struct directory {
|
||||
if(handle != INVALID_HANDLE_VALUE) {
|
||||
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
|
||||
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
string name = utf8_t(data.cFileName);
|
||||
if(wildcard(name, pattern)) list.append(string(name, "/"));
|
||||
string name = (const char*)utf8_t(data.cFileName);
|
||||
if(wildcard(name, pattern)) list.append(name);
|
||||
}
|
||||
}
|
||||
while(FindNextFile(handle, &data) != false) {
|
||||
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
|
||||
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
string name = utf8_t(data.cFileName);
|
||||
if(wildcard(name, pattern)) list.append(string(name, "/"));
|
||||
string name = (const char*)utf8_t(data.cFileName);
|
||||
if(wildcard(name, pattern)) list.append(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
FindClose(handle);
|
||||
}
|
||||
if(list.size() > 0) sort(&list[0], list.size());
|
||||
foreach(name, list) name.append("/"); //must append after sorting
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -70,12 +71,12 @@ struct directory {
|
||||
handle = FindFirstFile(utf16_t(path), &data);
|
||||
if(handle != INVALID_HANDLE_VALUE) {
|
||||
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
||||
string name = utf8_t(data.cFileName);
|
||||
string name = (const char*)utf8_t(data.cFileName);
|
||||
if(wildcard(name, pattern)) list.append(name);
|
||||
}
|
||||
while(FindNextFile(handle, &data) != false) {
|
||||
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
||||
string name = utf8_t(data.cFileName);
|
||||
string name = (const char*)utf8_t(data.cFileName);
|
||||
if(wildcard(name, pattern)) list.append(name);
|
||||
}
|
||||
}
|
||||
@@ -109,14 +110,14 @@ struct directory {
|
||||
if(!strcmp(ep->d_name, ".")) continue;
|
||||
if(!strcmp(ep->d_name, "..")) continue;
|
||||
if(ep->d_type & DT_DIR) {
|
||||
if(wildcard(ep->d_name, pattern)) list.append(string(ep->d_name, "/"));
|
||||
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
if(list.size() > 0) sort(&list[0], list.size());
|
||||
foreach(name, list) name.append("/"); //must append after sorting
|
||||
return list;
|
||||
|
||||
}
|
||||
|
||||
inline lstring directory::files(const string &pathname, const string &pattern) {
|
||||
|
@@ -12,7 +12,7 @@
|
||||
#include <dlfcn.h>
|
||||
#elif defined(PLATFORM_WIN)
|
||||
#include <windows.h>
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/windows/utf8.hpp>
|
||||
#endif
|
||||
|
||||
namespace nall {
|
||||
|
@@ -1,22 +1,14 @@
|
||||
#ifndef NALL_FILE_HPP
|
||||
#define NALL_FILE_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/windows/utf8.hpp>
|
||||
|
||||
namespace nall {
|
||||
inline FILE* fopen_utf8(const char *utf8_filename, const char *mode) {
|
||||
inline FILE* fopen_utf8(const string &utf8_filename, const char *mode) {
|
||||
#if !defined(_WIN32)
|
||||
return fopen(utf8_filename, mode);
|
||||
#else
|
||||
@@ -28,6 +20,25 @@ namespace nall {
|
||||
public:
|
||||
enum class mode : unsigned { read, write, readwrite, writeread };
|
||||
enum class index : unsigned { absolute, relative };
|
||||
enum class time : unsigned { create, modify, access };
|
||||
|
||||
static bool read(const string &filename, uint8_t *&data, unsigned &size) {
|
||||
file fp;
|
||||
if(fp.open(filename, mode::read) == false) return false;
|
||||
size = fp.size();
|
||||
data = new uint8_t[size];
|
||||
fp.read(data, size);
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write(const string &filename, const uint8_t *data, unsigned size) {
|
||||
file fp;
|
||||
if(fp.open(filename, mode::write) == false) return false;
|
||||
fp.write(data, size);
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t read() {
|
||||
if(!fp) return 0xff; //file not open
|
||||
@@ -142,52 +153,60 @@ namespace nall {
|
||||
return file_offset >= file_size;
|
||||
}
|
||||
|
||||
static bool exists(const char *fn) {
|
||||
static bool exists(const string &filename) {
|
||||
#if !defined(_WIN32)
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
struct stat64 data;
|
||||
return stat64(filename, &data) == 0;
|
||||
#else
|
||||
FILE *fp = _wfopen(utf16_t(fn), L"rb");
|
||||
struct __stat64 data;
|
||||
return _wstat64(utf16_t(filename), &data) == 0;
|
||||
#endif
|
||||
if(fp) {
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned size(const char *fn) {
|
||||
static uintmax_t size(const string &filename) {
|
||||
#if !defined(_WIN32)
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
struct stat64 data;
|
||||
stat64(filename, &data);
|
||||
#else
|
||||
FILE *fp = _wfopen(utf16_t(fn), L"rb");
|
||||
struct __stat64 data;
|
||||
_wstat64(utf16_t(filename), &data);
|
||||
#endif
|
||||
unsigned filesize = 0;
|
||||
if(fp) {
|
||||
fseek(fp, 0, SEEK_END);
|
||||
filesize = ftell(fp);
|
||||
fclose(fp);
|
||||
return S_ISREG(data.st_mode) ? data.st_size : 0u;
|
||||
}
|
||||
|
||||
static time_t timestamp(const string &filename, file::time mode = file::time::create) {
|
||||
#if !defined(_WIN32)
|
||||
struct stat64 data;
|
||||
stat64(filename, &data);
|
||||
#else
|
||||
struct __stat64 data;
|
||||
_wstat64(utf16_t(filename), &data);
|
||||
#endif
|
||||
switch(mode) { default:
|
||||
case file::time::create: return data.st_ctime;
|
||||
case file::time::modify: return data.st_mtime;
|
||||
case file::time::access: return data.st_atime;
|
||||
}
|
||||
return filesize;
|
||||
}
|
||||
|
||||
bool open() {
|
||||
return fp;
|
||||
}
|
||||
|
||||
bool open(const char *fn, mode mode_) {
|
||||
bool open(const string &filename, mode mode_) {
|
||||
if(fp) return false;
|
||||
|
||||
switch(file_mode = mode_) {
|
||||
#if !defined(_WIN32)
|
||||
case mode::read: fp = fopen(fn, "rb"); break;
|
||||
case mode::write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
|
||||
case mode::readwrite: fp = fopen(fn, "rb+"); break;
|
||||
case mode::writeread: fp = fopen(fn, "wb+"); break;
|
||||
case mode::read: fp = fopen(filename, "rb" ); break;
|
||||
case mode::write: fp = fopen(filename, "wb+"); break; //need read permission for buffering
|
||||
case mode::readwrite: fp = fopen(filename, "rb+"); break;
|
||||
case mode::writeread: fp = fopen(filename, "wb+"); break;
|
||||
#else
|
||||
case mode::read: fp = _wfopen(utf16_t(fn), L"rb"); break;
|
||||
case mode::write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
||||
case mode::readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
|
||||
case mode::writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
||||
case mode::read: fp = _wfopen(utf16_t(filename), L"rb" ); break;
|
||||
case mode::write: fp = _wfopen(utf16_t(filename), L"wb+"); break;
|
||||
case mode::readwrite: fp = _wfopen(utf16_t(filename), L"rb+"); break;
|
||||
case mode::writeread: fp = _wfopen(utf16_t(filename), L"wb+"); break;
|
||||
#endif
|
||||
}
|
||||
if(!fp) return false;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#define NALL_FILEMAP_HPP
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/windows/utf8.hpp>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -21,7 +21,7 @@ namespace nall {
|
||||
public:
|
||||
enum class mode : unsigned { read, write, readwrite, writeread };
|
||||
|
||||
bool opened() const { return p_opened(); }
|
||||
bool open() const { return p_open(); }
|
||||
bool open(const char *filename, mode mode_) { return p_open(filename, mode_); }
|
||||
void close() { return p_close(); }
|
||||
unsigned size() const { return p_size; }
|
||||
@@ -42,7 +42,7 @@ namespace nall {
|
||||
|
||||
HANDLE p_filehandle, p_maphandle;
|
||||
|
||||
bool p_opened() const {
|
||||
bool p_open() const {
|
||||
return p_handle;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace nall {
|
||||
|
||||
int p_fd;
|
||||
|
||||
bool p_opened() const {
|
||||
bool p_open() const {
|
||||
return p_handle;
|
||||
}
|
||||
|
||||
|
@@ -5,8 +5,14 @@
|
||||
#include <nall/concept.hpp>
|
||||
|
||||
#undef foreach
|
||||
#define foreach(iter, object) \
|
||||
|
||||
#define foreach2(iter, object) foreach3(iter, object, foreach_counter)
|
||||
#define foreach3(iter, object, foreach_counter) \
|
||||
for(unsigned foreach_counter = 0, foreach_limit = container_size(object), foreach_once = 0, foreach_broken = 0; foreach_counter < foreach_limit && foreach_broken == 0; foreach_counter++, foreach_once = 0) \
|
||||
for(auto &iter = object[foreach_counter]; foreach_once == 0 && (foreach_broken = 1); foreach_once++, foreach_broken = 0)
|
||||
|
||||
#define foreach_impl(...) foreach_decl(__VA_ARGS__, foreach3(__VA_ARGS__), foreach2(__VA_ARGS__), foreach_too_few_arguments)
|
||||
#define foreach_decl(_1, _2, _3, N, ...) N
|
||||
#define foreach(...) foreach_impl(__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
@@ -86,17 +86,17 @@ GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
|
||||
|
||||
if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit
|
||||
|
||||
xml << "<cartridge mapper='" << info.mapper << "'";
|
||||
if(info.rtc) xml << " rtc='true'";
|
||||
if(info.rumble) xml << " rumble='true'";
|
||||
xml << ">\n";
|
||||
xml.append("<cartridge mapper='", info.mapper, "'");
|
||||
if(info.rtc) xml.append(" rtc='true'");
|
||||
if(info.rumble) xml.append(" rumble='true'");
|
||||
xml.append(">\n");
|
||||
|
||||
xml << " <rom size='" << hex(romsize) << "'/>\n"; //TODO: trust/check info.romsize?
|
||||
xml.append(" <rom size='", hex(romsize), "'/>\n"); //TODO: trust/check info.romsize?
|
||||
|
||||
if(info.ramsize > 0)
|
||||
xml << " <ram size='" << hex(info.ramsize) << "' battery='" << info.battery << "'/>\n";
|
||||
xml.append(" <ram size='", hex(info.ramsize), "' battery='", info.battery, "'/>\n");
|
||||
|
||||
xml << "</cartridge>\n";
|
||||
xml.append("</cartridge>\n");
|
||||
xml.transform("'", "\"");
|
||||
}
|
||||
|
||||
|
87
bsnes/nall/gzip.hpp
Executable file
87
bsnes/nall/gzip.hpp
Executable file
@@ -0,0 +1,87 @@
|
||||
#ifndef NALL_GZIP_HPP
|
||||
#define NALL_GZIP_HPP
|
||||
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/inflate.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct gzip {
|
||||
string filename;
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
|
||||
bool decompress(const string &filename);
|
||||
bool decompress(const uint8_t *data, unsigned size);
|
||||
|
||||
gzip();
|
||||
~gzip();
|
||||
};
|
||||
|
||||
bool gzip::decompress(const string &filename) {
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
if(file::read(filename, data, size) == false) return false;
|
||||
bool result = decompress(data, size);
|
||||
delete[] data;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool gzip::decompress(const uint8_t *data, unsigned size) {
|
||||
if(size < 18) return false;
|
||||
if(data[0] != 0x1f) return false;
|
||||
if(data[1] != 0x8b) return false;
|
||||
unsigned cm = data[2];
|
||||
unsigned flg = data[3];
|
||||
unsigned mtime = data[4];
|
||||
mtime |= data[5] << 8;
|
||||
mtime |= data[6] << 16;
|
||||
mtime |= data[7] << 24;
|
||||
unsigned xfl = data[8];
|
||||
unsigned os = data[9];
|
||||
unsigned p = 10;
|
||||
unsigned isize = data[size - 4];
|
||||
isize |= data[size - 3] << 8;
|
||||
isize |= data[size - 2] << 16;
|
||||
isize |= data[size - 1] << 24;
|
||||
filename = "";
|
||||
|
||||
if(flg & 0x04) { //FEXTRA
|
||||
unsigned xlen = data[p + 0];
|
||||
xlen |= data[p + 1] << 8;
|
||||
p += 2 + xlen;
|
||||
}
|
||||
|
||||
if(flg & 0x08) { //FNAME
|
||||
char buffer[PATH_MAX];
|
||||
for(unsigned n = 0; n < PATH_MAX; n++, p++) {
|
||||
buffer[n] = data[p];
|
||||
if(data[p] == 0) break;
|
||||
}
|
||||
if(data[p++]) return false;
|
||||
filename = buffer;
|
||||
}
|
||||
|
||||
if(flg & 0x10) { //FCOMMENT
|
||||
while(data[p++]);
|
||||
}
|
||||
|
||||
if(flg & 0x02) { //FHCRC
|
||||
p += 2;
|
||||
}
|
||||
|
||||
this->size = isize;
|
||||
this->data = new uint8_t[this->size];
|
||||
return inflate(this->data, this->size, data + p, size - p - 8);
|
||||
}
|
||||
|
||||
gzip::gzip() : data(0) {
|
||||
}
|
||||
|
||||
gzip::~gzip() {
|
||||
if(data) delete[] data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
176
bsnes/nall/http.hpp
Executable file
176
bsnes/nall/http.hpp
Executable file
@@ -0,0 +1,176 @@
|
||||
#ifndef NALL_HTTP_HPP
|
||||
#define NALL_HTTP_HPP
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/string.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct http {
|
||||
string hostname;
|
||||
addrinfo *serverinfo;
|
||||
int serversocket;
|
||||
string header;
|
||||
|
||||
inline void download(const string &path, uint8_t *&data, unsigned &size) {
|
||||
data = 0;
|
||||
size = 0;
|
||||
|
||||
send({
|
||||
"GET ", path, " HTTP/1.1\r\n"
|
||||
"Host: ", hostname, "\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
});
|
||||
|
||||
header = downloadHeader();
|
||||
downloadContent(data, size);
|
||||
}
|
||||
|
||||
inline bool connect(string host, unsigned port) {
|
||||
hostname = host;
|
||||
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
int status = getaddrinfo(hostname, string(port), &hints, &serverinfo);
|
||||
if(status != 0) return false;
|
||||
|
||||
serversocket = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol);
|
||||
if(serversocket == -1) return false;
|
||||
|
||||
int result = ::connect(serversocket, serverinfo->ai_addr, serverinfo->ai_addrlen);
|
||||
if(result == -1) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool send(const string &data) {
|
||||
return send((const uint8_t*)(const char*)data, data.length());
|
||||
}
|
||||
|
||||
inline bool send(const uint8_t *data, unsigned size) {
|
||||
while(size) {
|
||||
int length = ::send(serversocket, (const char*)data, size, 0);
|
||||
if(length == -1) return false;
|
||||
data += length;
|
||||
size -= length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline string downloadHeader() {
|
||||
string output;
|
||||
do {
|
||||
char buffer[2];
|
||||
int length = recv(serversocket, buffer, 1, 0);
|
||||
if(length <= 0) return output;
|
||||
buffer[1] = 0;
|
||||
output.append(buffer);
|
||||
} while(output.endswith("\r\n\r\n") == false);
|
||||
return output;
|
||||
}
|
||||
|
||||
inline string downloadChunkLength() {
|
||||
string output;
|
||||
do {
|
||||
char buffer[2];
|
||||
int length = recv(serversocket, buffer, 1, 0);
|
||||
if(length <= 0) return output;
|
||||
buffer[1] = 0;
|
||||
output.append(buffer);
|
||||
} while(output.endswith("\r\n") == false);
|
||||
return output;
|
||||
}
|
||||
|
||||
inline void downloadContent(uint8_t *&data, unsigned &size) {
|
||||
unsigned capacity = 0;
|
||||
|
||||
if(header.iposition("\r\nTransfer-Encoding: chunked\r\n")) {
|
||||
while(true) {
|
||||
unsigned length = hex(downloadChunkLength());
|
||||
if(length == 0) break;
|
||||
capacity += length;
|
||||
data = (uint8_t*)realloc(data, capacity);
|
||||
|
||||
char buffer[length];
|
||||
while(length) {
|
||||
int packetlength = recv(serversocket, buffer, length, 0);
|
||||
if(packetlength <= 0) break;
|
||||
memcpy(data + size, buffer, packetlength);
|
||||
size += packetlength;
|
||||
length -= packetlength;
|
||||
}
|
||||
}
|
||||
} else if(auto position = header.iposition("\r\nContent-Length: ")) {
|
||||
unsigned length = decimal((const char*)header + position() + 16);
|
||||
while(length) {
|
||||
char buffer[256];
|
||||
int packetlength = recv(serversocket, buffer, min(256, length), 0);
|
||||
if(packetlength <= 0) break;
|
||||
capacity += packetlength;
|
||||
data = (uint8_t*)realloc(data, capacity);
|
||||
memcpy(data + size, buffer, packetlength);
|
||||
size += packetlength;
|
||||
length -= packetlength;
|
||||
}
|
||||
} else {
|
||||
while(true) {
|
||||
char buffer[256];
|
||||
int packetlength = recv(serversocket, buffer, 256, 0);
|
||||
if(packetlength <= 0) break;
|
||||
capacity += packetlength;
|
||||
data = (uint8_t*)realloc(data, capacity);
|
||||
memcpy(data + size, buffer, packetlength);
|
||||
size += packetlength;
|
||||
}
|
||||
}
|
||||
|
||||
data = (uint8_t*)realloc(data, capacity + 1);
|
||||
data[capacity] = 0;
|
||||
}
|
||||
|
||||
inline void disconnect() {
|
||||
close(serversocket);
|
||||
freeaddrinfo(serverinfo);
|
||||
serverinfo = 0;
|
||||
serversocket = -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline int close(int sock) {
|
||||
return closesocket(sock);
|
||||
}
|
||||
|
||||
inline http() {
|
||||
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(sock == INVALID_SOCKET && WSAGetLastError() == WSANOTINITIALISED) {
|
||||
WSADATA wsaData;
|
||||
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
WSACleanup();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
close(sock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
358
bsnes/nall/inflate.hpp
Executable file
358
bsnes/nall/inflate.hpp
Executable file
@@ -0,0 +1,358 @@
|
||||
#ifndef NALL_INFLATE_HPP
|
||||
#define NALL_INFLATE_HPP
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
namespace nall {
|
||||
|
||||
namespace puff {
|
||||
inline int puff(
|
||||
unsigned char *dest, unsigned long *destlen,
|
||||
unsigned char *source, unsigned long *sourcelen
|
||||
);
|
||||
}
|
||||
|
||||
inline bool inflate(
|
||||
uint8_t *target, unsigned targetLength,
|
||||
const uint8_t *source, unsigned sourceLength
|
||||
) {
|
||||
unsigned long tl = targetLength, sl = sourceLength;
|
||||
int result = puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
namespace puff {
|
||||
|
||||
//zlib/contrib/puff.c
|
||||
//version 2.1*
|
||||
//author: Mark Adler
|
||||
//license: zlib
|
||||
//ported by: byuu
|
||||
|
||||
//* I have corrected a bug in fixed(), where it was accessing uninitialized
|
||||
// memory: calling construct() with lencode prior to initializing lencode.count
|
||||
|
||||
enum {
|
||||
MAXBITS = 15,
|
||||
MAXLCODES = 286,
|
||||
MAXDCODES = 30,
|
||||
FIXLCODES = 288,
|
||||
MAXCODES = MAXLCODES + MAXDCODES,
|
||||
};
|
||||
|
||||
struct state {
|
||||
unsigned char *out;
|
||||
unsigned long outlen;
|
||||
unsigned long outcnt;
|
||||
|
||||
unsigned char *in;
|
||||
unsigned long inlen;
|
||||
unsigned long incnt;
|
||||
int bitbuf;
|
||||
int bitcnt;
|
||||
|
||||
jmp_buf env;
|
||||
};
|
||||
|
||||
struct huffman {
|
||||
short *count;
|
||||
short *symbol;
|
||||
};
|
||||
|
||||
inline int bits(state *s, int need) {
|
||||
long val;
|
||||
|
||||
val = s->bitbuf;
|
||||
while(s->bitcnt < need) {
|
||||
if(s->incnt == s->inlen) longjmp(s->env, 1);
|
||||
val |= (long)(s->in[s->incnt++]) << s->bitcnt;
|
||||
s->bitcnt += 8;
|
||||
}
|
||||
|
||||
s->bitbuf = (int)(val >> need);
|
||||
s->bitcnt -= need;
|
||||
|
||||
return (int)(val & ((1L << need) - 1));
|
||||
}
|
||||
|
||||
inline int stored(state *s) {
|
||||
unsigned len;
|
||||
|
||||
s->bitbuf = 0;
|
||||
s->bitcnt = 0;
|
||||
|
||||
if(s->incnt + 4 > s->inlen) return 2;
|
||||
len = s->in[s->incnt++];
|
||||
len |= s->in[s->incnt++] << 8;
|
||||
if(s->in[s->incnt++] != (~len & 0xff) ||
|
||||
s->in[s->incnt++] != ((~len >> 8) & 0xff)
|
||||
) return 2;
|
||||
|
||||
if(s->incnt + len > s->inlen) return 2;
|
||||
if(s->out != 0) {
|
||||
if(s->outcnt + len > s->outlen) return 1;
|
||||
while(len--) s->out[s->outcnt++] = s->in[s->incnt++];
|
||||
} else {
|
||||
s->outcnt += len;
|
||||
s->incnt += len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int decode(state *s, huffman *h) {
|
||||
int len, code, first, count, index, bitbuf, left;
|
||||
short *next;
|
||||
|
||||
bitbuf = s->bitbuf;
|
||||
left = s->bitcnt;
|
||||
code = first = index = 0;
|
||||
len = 1;
|
||||
next = h->count + 1;
|
||||
while(true) {
|
||||
while(left--) {
|
||||
code |= bitbuf & 1;
|
||||
bitbuf >>= 1;
|
||||
count = *next++;
|
||||
if(code - count < first) {
|
||||
s->bitbuf = bitbuf;
|
||||
s->bitcnt = (s->bitcnt - len) & 7;
|
||||
return h->symbol[index + (code - first)];
|
||||
}
|
||||
index += count;
|
||||
first += count;
|
||||
first <<= 1;
|
||||
code <<= 1;
|
||||
len++;
|
||||
}
|
||||
left = (MAXBITS + 1) - len;
|
||||
if(left == 0) break;
|
||||
if(s->incnt == s->inlen) longjmp(s->env, 1);
|
||||
bitbuf = s->in[s->incnt++];
|
||||
if(left > 8) left = 8;
|
||||
}
|
||||
|
||||
return -10;
|
||||
}
|
||||
|
||||
inline int construct(huffman *h, short *length, int n) {
|
||||
int symbol, len, left;
|
||||
short offs[MAXBITS + 1];
|
||||
|
||||
for(len = 0; len <= MAXBITS; len++) h->count[len] = 0;
|
||||
for(symbol = 0; symbol < n; symbol++) h->count[length[symbol]]++;
|
||||
if(h->count[0] == n) return 0;
|
||||
|
||||
left = 1;
|
||||
for(len = 1; len <= MAXBITS; len++) {
|
||||
left <<= 1;
|
||||
left -= h->count[len];
|
||||
if(left < 0) return left;
|
||||
}
|
||||
|
||||
offs[1] = 0;
|
||||
for(len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h->count[len];
|
||||
|
||||
for(symbol = 0; symbol < n; symbol++) {
|
||||
if(length[symbol] != 0) h->symbol[offs[length[symbol]]++] = symbol;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
inline int codes(state *s, huffman *lencode, huffman *distcode) {
|
||||
int symbol, len;
|
||||
unsigned dist;
|
||||
static const short lens[29] = {
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
|
||||
};
|
||||
static const short lext[29] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
static const short dists[30] = {
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
||||
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
||||
8193, 12289, 16385, 24577
|
||||
};
|
||||
static const short dext[30] = {
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
|
||||
12, 12, 13, 13
|
||||
};
|
||||
|
||||
do {
|
||||
symbol = decode(s, lencode);
|
||||
if(symbol < 0) return symbol;
|
||||
if(symbol < 256) {
|
||||
if(s->out != 0) {
|
||||
if(s->outcnt == s->outlen) return 1;
|
||||
s->out[s->outcnt] = symbol;
|
||||
}
|
||||
s->outcnt++;
|
||||
} else if(symbol > 256) {
|
||||
symbol -= 257;
|
||||
if(symbol >= 29) return -10;
|
||||
len = lens[symbol] + bits(s, lext[symbol]);
|
||||
|
||||
symbol = decode(s, distcode);
|
||||
if(symbol < 0) return symbol;
|
||||
dist = dists[symbol] + bits(s, dext[symbol]);
|
||||
#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
|
||||
if(dist > s->outcnt) return -11;
|
||||
#endif
|
||||
|
||||
if(s->out != 0) {
|
||||
if(s->outcnt + len > s->outlen) return 1;
|
||||
while(len--) {
|
||||
s->out[s->outcnt] =
|
||||
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
|
||||
dist > s->outcnt ? 0 :
|
||||
#endif
|
||||
s->out[s->outcnt - dist];
|
||||
s->outcnt++;
|
||||
}
|
||||
} else {
|
||||
s->outcnt += len;
|
||||
}
|
||||
}
|
||||
} while(symbol != 256);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int fixed(state *s) {
|
||||
static int virgin = 1;
|
||||
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
|
||||
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
|
||||
static huffman lencode, distcode;
|
||||
|
||||
if(virgin) {
|
||||
int symbol = 0;
|
||||
short lengths[FIXLCODES];
|
||||
|
||||
lencode.count = lencnt;
|
||||
lencode.symbol = lensym;
|
||||
distcode.count = distcnt;
|
||||
distcode.symbol = distsym;
|
||||
|
||||
for(; symbol < 144; symbol++) lengths[symbol] = 8;
|
||||
for(; symbol < 256; symbol++) lengths[symbol] = 9;
|
||||
for(; symbol < 280; symbol++) lengths[symbol] = 7;
|
||||
for(; symbol < FIXLCODES; symbol++) lengths[symbol] = 8;
|
||||
construct(&lencode, lengths, FIXLCODES);
|
||||
|
||||
for(symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5;
|
||||
construct(&distcode, lengths, MAXDCODES);
|
||||
|
||||
virgin = 0;
|
||||
}
|
||||
|
||||
return codes(s, &lencode, &distcode);
|
||||
}
|
||||
|
||||
inline int dynamic(state *s) {
|
||||
int nlen, ndist, ncode, index, err;
|
||||
short lengths[MAXCODES];
|
||||
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
|
||||
short distcnt[MAXBITS + 1], distsym[MAXDCODES];
|
||||
huffman lencode, distcode;
|
||||
static const short order[19] = {
|
||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||
};
|
||||
|
||||
lencode.count = lencnt;
|
||||
lencode.symbol = lensym;
|
||||
distcode.count = distcnt;
|
||||
distcode.symbol = distsym;
|
||||
|
||||
nlen = bits(s, 5) + 257;
|
||||
ndist = bits(s, 5) + 1;
|
||||
ncode = bits(s, 4) + 4;
|
||||
if(nlen > MAXLCODES || ndist > MAXDCODES) return -3;
|
||||
|
||||
for(index = 0; index < ncode; index++) lengths[order[index]] = bits(s, 3);
|
||||
for(; index < 19; index++) lengths[order[index]] = 0;
|
||||
|
||||
err = construct(&lencode, lengths, 19);
|
||||
if(err != 0) return -4;
|
||||
|
||||
index = 0;
|
||||
while(index < nlen + ndist) {
|
||||
int symbol, len;
|
||||
|
||||
symbol = decode(s, &lencode);
|
||||
if(symbol < 16) {
|
||||
lengths[index++] = symbol;
|
||||
} else {
|
||||
len = 0;
|
||||
if(symbol == 16) {
|
||||
if(index == 0) return -5;
|
||||
len = lengths[index - 1];
|
||||
symbol = 3 + bits(s, 2);
|
||||
} else if(symbol == 17) {
|
||||
symbol = 3 + bits(s, 3);
|
||||
} else {
|
||||
symbol = 11 + bits(s, 7);
|
||||
}
|
||||
if(index + symbol > nlen + ndist) return -6;
|
||||
while(symbol--) lengths[index++] = len;
|
||||
}
|
||||
}
|
||||
|
||||
if(lengths[256] == 0) return -9;
|
||||
|
||||
err = construct(&lencode, lengths, nlen);
|
||||
if(err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) return -7;
|
||||
|
||||
err = construct(&distcode, lengths + nlen, ndist);
|
||||
if(err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) return -8;
|
||||
|
||||
return codes(s, &lencode, &distcode);
|
||||
}
|
||||
|
||||
inline int puff(
|
||||
unsigned char *dest, unsigned long *destlen,
|
||||
unsigned char *source, unsigned long *sourcelen
|
||||
) {
|
||||
state s;
|
||||
int last, type, err;
|
||||
|
||||
s.out = dest;
|
||||
s.outlen = *destlen;
|
||||
s.outcnt = 0;
|
||||
|
||||
s.in = source;
|
||||
s.inlen = *sourcelen;
|
||||
s.incnt = 0;
|
||||
s.bitbuf = 0;
|
||||
s.bitcnt = 0;
|
||||
|
||||
if(setjmp(s.env) != 0) {
|
||||
err = 2;
|
||||
} else {
|
||||
do {
|
||||
last = bits(&s, 1);
|
||||
type = bits(&s, 2);
|
||||
err = type == 0 ? stored(&s)
|
||||
: type == 1 ? fixed(&s)
|
||||
: type == 2 ? dynamic(&s)
|
||||
: -1;
|
||||
if(err != 0) break;
|
||||
} while(!last);
|
||||
}
|
||||
|
||||
if(err <= 0) {
|
||||
*destlen = s.outcnt;
|
||||
*sourcelen = s.incnt;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -110,7 +110,7 @@ struct Keyboard {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return string() << "KB" << ID << "::" << KeyboardScancodeName[index];
|
||||
return { "KB", ID, "::", KeyboardScancodeName[index] };
|
||||
}
|
||||
|
||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
||||
@@ -207,7 +207,7 @@ struct Mouse {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return string() << "MS" << ID << "::" << MouseScancodeName[index];
|
||||
return { "MS", ID, "::", MouseScancodeName[index] };
|
||||
}
|
||||
|
||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
||||
@@ -330,7 +330,7 @@ struct Joypad {
|
||||
index = code - (Base + Size * i);
|
||||
}
|
||||
}
|
||||
return string() << "JP" << ID << "::" << JoypadScancodeName[index];
|
||||
return { "JP", ID, "::", JoypadScancodeName[index] };
|
||||
}
|
||||
|
||||
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
||||
|
@@ -2,14 +2,13 @@
|
||||
#define NALL_LZSS_HPP
|
||||
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/new.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
namespace nall {
|
||||
class lzss {
|
||||
public:
|
||||
static bool encode(uint8_t *&output, unsigned &outlength, const uint8_t *input, unsigned inlength) {
|
||||
output = new(zeromemory) uint8_t[inlength * 9 / 8 + 9];
|
||||
output = new uint8_t[inlength * 9 / 8 + 9]();
|
||||
|
||||
unsigned i = 0, o = 0;
|
||||
while(i < inlength) {
|
||||
@@ -52,7 +51,7 @@ namespace nall {
|
||||
}
|
||||
|
||||
static bool decode(uint8_t *&output, const uint8_t *input, unsigned length) {
|
||||
output = new(zeromemory) uint8_t[length];
|
||||
output = new uint8_t[length]();
|
||||
|
||||
unsigned i = 0, o = 0;
|
||||
while(o < length) {
|
||||
|
@@ -1,7 +1,12 @@
|
||||
#ifndef NALL_PLATFORM_HPP
|
||||
#define NALL_PLATFORM_HPP
|
||||
|
||||
#include <nall/utf8.hpp>
|
||||
#if defined(_WIN32)
|
||||
//minimum version needed for _wstat64, etc
|
||||
#undef __MSVCRT_VERSION__
|
||||
#define __MSVCRT_VERSION__ 0x0601
|
||||
#include <nall/windows/utf8.hpp>
|
||||
#endif
|
||||
|
||||
//=========================
|
||||
//standard platform headers
|
||||
@@ -18,16 +23,19 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <shlobj.h>
|
||||
#include <wchar.h>
|
||||
#undef interface
|
||||
#define dllexport __declspec(dllexport)
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/stat.h>
|
||||
#define dllexport
|
||||
#endif
|
||||
|
||||
@@ -53,11 +61,11 @@
|
||||
#if defined(_WIN32)
|
||||
#define getcwd _getcwd
|
||||
#define ftruncate _chsize
|
||||
#define putenv _putenv
|
||||
#define mkdir(n, m) _wmkdir(nall::utf16_t(n))
|
||||
#define putenv _putenv
|
||||
#define rmdir _rmdir
|
||||
#define vsnprintf _vsnprintf
|
||||
#define usleep(n) Sleep(n / 1000)
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
//================
|
||||
|
423
bsnes/nall/png.hpp
Executable file
423
bsnes/nall/png.hpp
Executable file
@@ -0,0 +1,423 @@
|
||||
#ifndef NALL_PNG_HPP
|
||||
#define NALL_PNG_HPP
|
||||
|
||||
//PNG image decoder
|
||||
//author: byuu
|
||||
|
||||
#include <nall/inflate.hpp>
|
||||
#include <nall/string.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct png {
|
||||
uint32_t *data;
|
||||
unsigned size;
|
||||
|
||||
struct Info {
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned bitDepth;
|
||||
unsigned colorType;
|
||||
unsigned compressionMethod;
|
||||
unsigned filterType;
|
||||
unsigned interlaceMethod;
|
||||
|
||||
unsigned bytesPerPixel;
|
||||
unsigned pitch;
|
||||
|
||||
uint8_t palette[256][3];
|
||||
} info;
|
||||
|
||||
uint8_t *rawData;
|
||||
unsigned rawSize;
|
||||
|
||||
inline bool decode(const string &filename);
|
||||
inline bool decode(const uint8_t *sourceData, unsigned sourceSize);
|
||||
inline void transform();
|
||||
inline void alphaTransform(uint32_t rgb = 0xffffff);
|
||||
inline png();
|
||||
inline ~png();
|
||||
|
||||
protected:
|
||||
enum class FourCC : unsigned {
|
||||
IHDR = 0x49484452,
|
||||
PLTE = 0x504c5445,
|
||||
IDAT = 0x49444154,
|
||||
IEND = 0x49454e44,
|
||||
};
|
||||
|
||||
static const unsigned interlace[7][4];
|
||||
unsigned bitpos;
|
||||
|
||||
inline unsigned inflateSize();
|
||||
inline bool deinterlace(const uint8_t *&inputData, unsigned pass);
|
||||
inline bool filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height);
|
||||
inline unsigned read(const uint8_t *data, unsigned length);
|
||||
inline unsigned decode(const uint8_t *&data);
|
||||
inline unsigned readbits(const uint8_t *&data);
|
||||
inline unsigned scale(unsigned n);
|
||||
};
|
||||
|
||||
bool png::decode(const string &filename) {
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
if(file::read(filename, data, size) == false) return false;
|
||||
bool result = decode(data, size);
|
||||
delete[] data;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool png::decode(const uint8_t *sourceData, unsigned sourceSize) {
|
||||
if(sourceSize < 8) return false;
|
||||
if(read(sourceData + 0, 4) != 0x89504e47) return false;
|
||||
if(read(sourceData + 4, 4) != 0x0d0a1a0a) return false;
|
||||
|
||||
uint8_t *compressedData = 0;
|
||||
unsigned compressedSize = 0;
|
||||
|
||||
unsigned offset = 8;
|
||||
while(offset < sourceSize) {
|
||||
unsigned length = read(sourceData + offset + 0, 4);
|
||||
unsigned fourCC = read(sourceData + offset + 4, 4);
|
||||
unsigned checksum = read(sourceData + offset + 8 + length, 4);
|
||||
|
||||
if(fourCC == (unsigned)FourCC::IHDR) {
|
||||
info.width = read(sourceData + offset + 8, 4);
|
||||
info.height = read(sourceData + offset + 12, 4);
|
||||
info.bitDepth = read(sourceData + offset + 16, 1);
|
||||
info.colorType = read(sourceData + offset + 17, 1);
|
||||
info.compressionMethod = read(sourceData + offset + 18, 1);
|
||||
info.filterType = read(sourceData + offset + 19, 1);
|
||||
info.interlaceMethod = read(sourceData + offset + 20, 1);
|
||||
|
||||
if(info.bitDepth == 0 || info.bitDepth > 16) return false;
|
||||
if(info.bitDepth & (info.bitDepth - 1)) return false; //not a power of two
|
||||
if(info.compressionMethod != 0) return false;
|
||||
if(info.filterType != 0) return false;
|
||||
if(info.interlaceMethod != 0 && info.interlaceMethod != 1) return false;
|
||||
|
||||
switch(info.colorType) {
|
||||
case 0: info.bytesPerPixel = info.bitDepth * 1; break; //L
|
||||
case 2: info.bytesPerPixel = info.bitDepth * 3; break; //R,G,B
|
||||
case 3: info.bytesPerPixel = info.bitDepth * 1; break; //P
|
||||
case 4: info.bytesPerPixel = info.bitDepth * 2; break; //L,A
|
||||
case 6: info.bytesPerPixel = info.bitDepth * 4; break; //R,G,B,A
|
||||
default: return false;
|
||||
}
|
||||
|
||||
if(info.colorType == 2 || info.colorType == 4 || info.colorType == 6)
|
||||
if(info.bitDepth != 8 && info.bitDepth != 16) return false;
|
||||
if(info.colorType == 3 && info.bitDepth == 16) return false;
|
||||
|
||||
info.bytesPerPixel = (info.bytesPerPixel + 7) / 8;
|
||||
info.pitch = (int)info.width * info.bytesPerPixel;
|
||||
}
|
||||
|
||||
if(fourCC == (unsigned)FourCC::PLTE) {
|
||||
if(length % 3) return false;
|
||||
for(unsigned n = 0, p = offset + 8; n < length / 3; n++) {
|
||||
info.palette[n][0] = sourceData[p++];
|
||||
info.palette[n][1] = sourceData[p++];
|
||||
info.palette[n][2] = sourceData[p++];
|
||||
}
|
||||
}
|
||||
|
||||
if(fourCC == (unsigned)FourCC::IDAT) {
|
||||
compressedData = (uint8_t*)realloc(compressedData, compressedSize + length);
|
||||
memcpy(compressedData + compressedSize, sourceData + offset + 8, length);
|
||||
compressedSize += length;
|
||||
}
|
||||
|
||||
if(fourCC == (unsigned)FourCC::IEND) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += 4 + 4 + length + 4;
|
||||
}
|
||||
|
||||
unsigned interlacedSize = inflateSize();
|
||||
uint8_t *interlacedData = new uint8_t[interlacedSize];
|
||||
|
||||
bool result = inflate(interlacedData, interlacedSize, compressedData + 2, compressedSize - 6);
|
||||
delete[] compressedData;
|
||||
|
||||
if(result == false) {
|
||||
delete[] interlacedData;
|
||||
return false;
|
||||
}
|
||||
|
||||
rawSize = info.width * info.height * info.bytesPerPixel;
|
||||
rawData = new uint8_t[rawSize];
|
||||
|
||||
if(info.interlaceMethod == 0) {
|
||||
if(filter(rawData, interlacedData, info.width, info.height) == false) {
|
||||
delete[] interlacedData;
|
||||
delete[] rawData;
|
||||
rawData = 0;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const uint8_t *passData = interlacedData;
|
||||
for(unsigned pass = 0; pass < 7; pass++) {
|
||||
if(deinterlace(passData, pass) == false) {
|
||||
delete[] interlacedData;
|
||||
delete[] rawData;
|
||||
rawData = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] interlacedData;
|
||||
return true;
|
||||
}
|
||||
|
||||
const unsigned png::interlace[7][4] = {
|
||||
//x-distance, y-distance, x-origin, y-origin
|
||||
{ 8, 8, 0, 0 },
|
||||
{ 8, 8, 4, 0 },
|
||||
{ 4, 8, 0, 4 },
|
||||
{ 4, 4, 2, 0 },
|
||||
{ 2, 4, 0, 2 },
|
||||
{ 2, 2, 1, 0 },
|
||||
{ 1, 2, 0, 1 },
|
||||
};
|
||||
|
||||
unsigned png::inflateSize() {
|
||||
if(info.interlaceMethod == 0) {
|
||||
return info.width * info.height * info.bytesPerPixel + info.height;
|
||||
}
|
||||
|
||||
unsigned size = 0;
|
||||
for(unsigned pass = 0; pass < 7; pass++) {
|
||||
unsigned xd = interlace[pass][0], yd = interlace[pass][1];
|
||||
unsigned xo = interlace[pass][2], yo = interlace[pass][3];
|
||||
unsigned width = (info.width + (xd - xo - 1)) / xd;
|
||||
unsigned height = (info.height + (yd - yo - 1)) / yd;
|
||||
if(width == 0 || height == 0) continue;
|
||||
size += width * height * info.bytesPerPixel + height;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool png::deinterlace(const uint8_t *&inputData, unsigned pass) {
|
||||
unsigned xd = interlace[pass][0], yd = interlace[pass][1];
|
||||
unsigned xo = interlace[pass][2], yo = interlace[pass][3];
|
||||
unsigned width = (info.width + (xd - xo - 1)) / xd;
|
||||
unsigned height = (info.height + (yd - yo - 1)) / yd;
|
||||
if(width == 0 || height == 0) return true;
|
||||
|
||||
unsigned outputSize = width * height * info.bytesPerPixel;
|
||||
uint8_t *outputData = new uint8_t[outputSize];
|
||||
bool result = filter(outputData, inputData, width, height);
|
||||
|
||||
const uint8_t *rd = outputData;
|
||||
for(unsigned y = yo; y < info.height; y += yd) {
|
||||
uint8_t *wr = rawData + y * info.pitch;
|
||||
for(unsigned x = xo; x < info.width; x += xd) {
|
||||
for(unsigned b = 0; b < info.bytesPerPixel; b++) {
|
||||
wr[x * info.bytesPerPixel + b] = *rd++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inputData += outputSize + height;
|
||||
delete[] outputData;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool png::filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height) {
|
||||
uint8_t *wr = outputData;
|
||||
const uint8_t *rd = inputData;
|
||||
int bpp = info.bytesPerPixel, pitch = width * bpp;
|
||||
for(int y = 0; y < height; y++) {
|
||||
uint8_t filter = *rd++;
|
||||
|
||||
switch(filter) {
|
||||
case 0x00: //None
|
||||
for(int x = 0; x < pitch; x++) {
|
||||
wr[x] = rd[x];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x01: //Subtract
|
||||
for(int x = 0; x < pitch; x++) {
|
||||
wr[x] = rd[x] + (x - bpp < 0 ? 0 : wr[x - bpp]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x02: //Above
|
||||
for(int x = 0; x < pitch; x++) {
|
||||
wr[x] = rd[x] + (y - 1 < 0 ? 0 : wr[x - pitch]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x03: //Average
|
||||
for(int x = 0; x < pitch; x++) {
|
||||
short a = x - bpp < 0 ? 0 : wr[x - bpp];
|
||||
short b = y - 1 < 0 ? 0 : wr[x - pitch];
|
||||
|
||||
wr[x] = rd[x] + (uint8_t)((a + b) / 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x04: //Paeth
|
||||
for(int x = 0; x < pitch; x++) {
|
||||
short a = x - bpp < 0 ? 0 : wr[x - bpp];
|
||||
short b = y - 1 < 0 ? 0 : wr[x - pitch];
|
||||
short c = x - bpp < 0 || y - 1 < 0 ? 0 : wr[x - pitch - bpp];
|
||||
|
||||
short p = a + b - c;
|
||||
short pa = p > a ? p - a : a - p;
|
||||
short pb = p > b ? p - b : b - p;
|
||||
short pc = p > c ? p - c : c - p;
|
||||
|
||||
uint8_t paeth = (uint8_t)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c);
|
||||
|
||||
wr[x] = rd[x] + paeth;
|
||||
}
|
||||
break;
|
||||
|
||||
default: //Invalid
|
||||
return false;
|
||||
}
|
||||
|
||||
rd += pitch;
|
||||
wr += pitch;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned png::read(const uint8_t *data, unsigned length) {
|
||||
unsigned result = 0;
|
||||
while(length--) result = (result << 8) | (*data++);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned png::decode(const uint8_t *&data) {
|
||||
unsigned p, r, g, b, a;
|
||||
|
||||
switch(info.colorType) {
|
||||
case 0: //L
|
||||
r = g = b = scale(readbits(data));
|
||||
a = 0xff;
|
||||
break;
|
||||
case 2: //R,G,B
|
||||
r = scale(readbits(data));
|
||||
g = scale(readbits(data));
|
||||
b = scale(readbits(data));
|
||||
a = 0xff;
|
||||
break;
|
||||
case 3: //P
|
||||
p = readbits(data);
|
||||
r = info.palette[p][0];
|
||||
g = info.palette[p][1];
|
||||
b = info.palette[p][2];
|
||||
a = 0xff;
|
||||
break;
|
||||
case 4: //L,A
|
||||
r = g = b = scale(readbits(data));
|
||||
a = scale(readbits(data));
|
||||
break;
|
||||
case 6: //R,G,B,A
|
||||
r = scale(readbits(data));
|
||||
g = scale(readbits(data));
|
||||
b = scale(readbits(data));
|
||||
a = scale(readbits(data));
|
||||
break;
|
||||
}
|
||||
|
||||
return (a << 24) | (r << 16) | (g << 8) | (b << 0);
|
||||
}
|
||||
|
||||
unsigned png::readbits(const uint8_t *&data) {
|
||||
unsigned result = 0;
|
||||
switch(info.bitDepth) {
|
||||
case 1:
|
||||
result = (*data >> bitpos) & 1;
|
||||
bitpos++;
|
||||
if(bitpos == 8) { data++; bitpos = 0; }
|
||||
break;
|
||||
case 2:
|
||||
result = (*data >> bitpos) & 3;
|
||||
bitpos += 2;
|
||||
if(bitpos == 8) { data++; bitpos = 0; }
|
||||
break;
|
||||
case 4:
|
||||
result = (*data >> bitpos) & 15;
|
||||
bitpos += 4;
|
||||
if(bitpos == 8) { data++; bitpos = 0; }
|
||||
break;
|
||||
case 8:
|
||||
result = *data++;
|
||||
break;
|
||||
case 16:
|
||||
result = (data[0] << 8) | (data[1] << 0);
|
||||
data += 2;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned png::scale(unsigned n) {
|
||||
switch(info.bitDepth) {
|
||||
case 1: return n ? 0xff : 0x00;
|
||||
case 2: return n * 0x55;
|
||||
case 4: return n * 0x11;
|
||||
case 8: return n;
|
||||
case 16: return n >> 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void png::transform() {
|
||||
if(data) delete[] data;
|
||||
data = new uint32_t[info.width * info.height];
|
||||
|
||||
bitpos = 0;
|
||||
const uint8_t *rd = rawData;
|
||||
for(unsigned y = 0; y < info.height; y++) {
|
||||
uint32_t *wr = data + y * info.width;
|
||||
for(unsigned x = 0; x < info.width; x++) {
|
||||
wr[x] = decode(rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void png::alphaTransform(uint32_t rgb) {
|
||||
transform();
|
||||
|
||||
uint8_t ir = rgb >> 16;
|
||||
uint8_t ig = rgb >> 8;
|
||||
uint8_t ib = rgb >> 0;
|
||||
|
||||
uint32_t *p = data;
|
||||
for(unsigned y = 0; y < info.height; y++) {
|
||||
for(unsigned x = 0; x < info.width; x++) {
|
||||
uint32_t pixel = *p;
|
||||
uint8_t a = pixel >> 24;
|
||||
uint8_t r = pixel >> 16;
|
||||
uint8_t g = pixel >> 8;
|
||||
uint8_t b = pixel >> 0;
|
||||
|
||||
r = (r * a) + (ir * (255 - a)) >> 8;
|
||||
g = (g * a) + (ig * (255 - a)) >> 8;
|
||||
b = (b * a) + (ib * (255 - a)) >> 8;
|
||||
|
||||
*p++ = (255 << 24) | (r << 16) | (g << 8) | (b << 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
png::png() : data(0), rawData(0) {
|
||||
}
|
||||
|
||||
png::~png() {
|
||||
if(data) delete[] data;
|
||||
if(rawData) delete[] rawData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
32
bsnes/nall/public_cast.hpp
Executable file
32
bsnes/nall/public_cast.hpp
Executable file
@@ -0,0 +1,32 @@
|
||||
#ifndef NALL_PUBLIC_CAST_HPP
|
||||
#define NALL_PUBLIC_CAST_HPP
|
||||
|
||||
//this is a proof-of-concept-*only* C++ access-privilege elevation exploit.
|
||||
//this code is 100% legal C++, per C++98 section 14.7.2 paragraph 8:
|
||||
//"access checking rules do not apply to names in explicit instantiations."
|
||||
//usage example:
|
||||
|
||||
//struct N { typedef void (Class::*)(); };
|
||||
//template class public_cast<N, &Class::Reference>;
|
||||
//(class.*public_cast<N>::value);
|
||||
|
||||
//Class::Reference may be public, protected or private
|
||||
//Class::Reference may be a function, object or variable
|
||||
|
||||
namespace nall {
|
||||
template<typename T, typename T::type... P> struct public_cast;
|
||||
|
||||
template<typename T> struct public_cast<T> {
|
||||
static typename T::type value;
|
||||
};
|
||||
|
||||
template<typename T> typename T::type public_cast<T>::value;
|
||||
|
||||
template<typename T, typename T::type P> struct public_cast<T, P> {
|
||||
static typename T::type value;
|
||||
};
|
||||
|
||||
template<typename T, typename T::type P> typename T::type public_cast<T, P>::value = public_cast<T>::value = P;
|
||||
}
|
||||
|
||||
#endif
|
@@ -8,12 +8,20 @@ namespace nall {
|
||||
return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320);
|
||||
}
|
||||
|
||||
struct random_cyclic {
|
||||
unsigned seed;
|
||||
inline unsigned operator()() {
|
||||
return seed = (seed >> 1) ^ (((seed & 1) - 1) & 0xedb88320);
|
||||
struct random_lfsr {
|
||||
inline void seed(unsigned seed__) {
|
||||
seed_ = seed__;
|
||||
}
|
||||
random_cyclic() : seed(0) {}
|
||||
|
||||
inline unsigned operator()() {
|
||||
return seed_ = (seed_ >> 1) ^ (((seed_ & 1) - 1) & 0xedb88320);
|
||||
}
|
||||
|
||||
random_lfsr() : seed_(0) {
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned seed_;
|
||||
};
|
||||
}
|
||||
|
||||
|
103
bsnes/nall/reference_array.hpp
Executable file
103
bsnes/nall/reference_array.hpp
Executable file
@@ -0,0 +1,103 @@
|
||||
#ifndef NALL_REFERENCE_ARRAY_HPP
|
||||
#define NALL_REFERENCE_ARRAY_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <nall/bit.hpp>
|
||||
#include <nall/concept.hpp>
|
||||
|
||||
namespace nall {
|
||||
template<typename T> struct reference_array {
|
||||
protected:
|
||||
typedef typename std::remove_reference<T>::type *Tptr;
|
||||
Tptr *pool;
|
||||
unsigned poolsize, buffersize;
|
||||
|
||||
public:
|
||||
unsigned size() const { return buffersize; }
|
||||
unsigned capacity() const { return poolsize; }
|
||||
|
||||
void reset() {
|
||||
if(pool) free(pool);
|
||||
pool = 0;
|
||||
poolsize = 0;
|
||||
buffersize = 0;
|
||||
}
|
||||
|
||||
void reserve(unsigned newsize) {
|
||||
if(newsize == poolsize) return;
|
||||
|
||||
pool = (Tptr*)realloc(pool, newsize * sizeof(T));
|
||||
poolsize = newsize;
|
||||
buffersize = min(buffersize, newsize);
|
||||
}
|
||||
|
||||
void resize(unsigned newsize) {
|
||||
if(newsize > poolsize) reserve(bit::round(newsize));
|
||||
buffersize = newsize;
|
||||
}
|
||||
|
||||
void append(const T data) {
|
||||
unsigned index = buffersize++;
|
||||
if(index >= poolsize) resize(index + 1);
|
||||
pool[index] = &data;
|
||||
}
|
||||
|
||||
template<typename... Args> reference_array(Args&... args) : pool(0), poolsize(0), buffersize(0) {
|
||||
construct(args...);
|
||||
}
|
||||
|
||||
~reference_array() {
|
||||
reset();
|
||||
}
|
||||
|
||||
reference_array& operator=(const reference_array &source) {
|
||||
if(pool) free(pool);
|
||||
buffersize = source.buffersize;
|
||||
poolsize = source.poolsize;
|
||||
pool = (Tptr*)malloc(sizeof(T) * poolsize);
|
||||
memcpy(pool, source.pool, sizeof(T) * buffersize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
reference_array& operator=(const reference_array &&source) {
|
||||
if(pool) free(pool);
|
||||
pool = source.pool;
|
||||
poolsize = source.poolsize;
|
||||
buffersize = source.buffersize;
|
||||
source.pool = 0;
|
||||
source.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T operator[](unsigned index) {
|
||||
if(index >= buffersize) throw "reference_array[] out of bounds";
|
||||
return *pool[index];
|
||||
}
|
||||
|
||||
inline const T operator[](unsigned index) const {
|
||||
if(index >= buffersize) throw "reference_array[] out of bounds";
|
||||
return *pool[index];
|
||||
}
|
||||
|
||||
private:
|
||||
void construct() {
|
||||
}
|
||||
|
||||
void construct(const reference_array &source) {
|
||||
operator=(source);
|
||||
}
|
||||
|
||||
void construct(const reference_array &&source) {
|
||||
operator=(std::move(source));
|
||||
}
|
||||
|
||||
template<typename... Args> void construct(T data, Args&... args) {
|
||||
append(data);
|
||||
construct(args...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct has_size<reference_array<T>> { enum { value = true }; };
|
||||
}
|
||||
|
||||
#endif
|
61
bsnes/nall/resource.hpp
Executable file
61
bsnes/nall/resource.hpp
Executable file
@@ -0,0 +1,61 @@
|
||||
#ifndef NALL_RESOURCE_HPP
|
||||
#define NALL_RESOURCE_HPP
|
||||
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/zip.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct resource {
|
||||
//create resource with "zip -9 resource.zip resource"
|
||||
static bool encode(const char *outputFilename, const char *inputFilename) {
|
||||
file fp;
|
||||
if(fp.open(inputFilename, file::mode::read) == false) return false;
|
||||
unsigned size = fp.size();
|
||||
uint8_t *data = new uint8_t[size];
|
||||
fp.read(data, size);
|
||||
fp.close();
|
||||
|
||||
fp.open(outputFilename, file::mode::write);
|
||||
fp.print("static const uint8_t data[", size, "] = {\n");
|
||||
uint8_t *p = data;
|
||||
while(size) {
|
||||
fp.print(" ");
|
||||
for(unsigned n = 0; n < 32 && size; n++, size--) {
|
||||
fp.print((unsigned)*p++, ",");
|
||||
}
|
||||
fp.print("\n");
|
||||
}
|
||||
fp.print("};\n");
|
||||
fp.close();
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
|
||||
//extract first file from ZIP archive
|
||||
bool decode(const uint8_t *cdata, unsigned csize) {
|
||||
if(data) delete[] data;
|
||||
|
||||
zip archive;
|
||||
if(archive.open(cdata, csize) == false) return false;
|
||||
if(archive.file.size() == 0) return false;
|
||||
bool result = archive.extract(archive.file[0], data, size);
|
||||
archive.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
resource() : data(0), size(0) {
|
||||
}
|
||||
|
||||
~resource() {
|
||||
if(data) delete[] data;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -3,6 +3,8 @@
|
||||
|
||||
//author: vladitx
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
namespace nall {
|
||||
#define PTR(t, a) ((t*)(a))
|
||||
|
||||
@@ -49,7 +51,7 @@ namespace nall {
|
||||
uint64_t len;
|
||||
};
|
||||
|
||||
void sha256_init(sha256_ctx *p) {
|
||||
inline void sha256_init(sha256_ctx *p) {
|
||||
memset(p, 0, sizeof(sha256_ctx));
|
||||
memcpy(p->h, T_H, sizeof(T_H));
|
||||
}
|
||||
@@ -90,7 +92,7 @@ namespace nall {
|
||||
p->inlen = 0;
|
||||
}
|
||||
|
||||
void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) {
|
||||
inline void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) {
|
||||
unsigned l;
|
||||
p->len += len;
|
||||
|
||||
@@ -107,7 +109,7 @@ namespace nall {
|
||||
}
|
||||
}
|
||||
|
||||
void sha256_final(sha256_ctx *p) {
|
||||
inline void sha256_final(sha256_ctx *p) {
|
||||
uint64_t len;
|
||||
p->in[p->inlen++] = 0x80;
|
||||
|
||||
@@ -124,7 +126,7 @@ namespace nall {
|
||||
sha256_block(p);
|
||||
}
|
||||
|
||||
void sha256_hash(sha256_ctx *p, uint8_t *s) {
|
||||
inline void sha256_hash(sha256_ctx *p, uint8_t *s) {
|
||||
uint32_t *t = (uint32_t*)s;
|
||||
for(unsigned i = 0; i < 8; i++) ST32BE(t++, p->h[i]);
|
||||
}
|
||||
|
@@ -111,422 +111,426 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
string xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
|
||||
if(type == TypeBsx) {
|
||||
xml << "<cartridge/>";
|
||||
xml.append("<cartridge/>");
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == TypeSufamiTurbo) {
|
||||
xml << "<cartridge/>";
|
||||
xml.append("<cartridge/>");
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == TypeGameBoy) {
|
||||
xml << "<cartridge rtc='" << gameboy_has_rtc(data, size) << "'>\n";
|
||||
xml.append("<cartridge rtc='", gameboy_has_rtc(data, size), "'>\n");
|
||||
if(gameboy_ram_size(data, size) > 0) {
|
||||
xml << " <ram size='" << hex(gameboy_ram_size(data, size)) << "'/>\n";
|
||||
xml.append(" <ram size='0x", hex(gameboy_ram_size(data, size)), "'/>\n");
|
||||
}
|
||||
xml << "</cartridge>\n";
|
||||
xml.append("</cartridge>\n");
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
xml << "<cartridge";
|
||||
xml.append("<cartridge");
|
||||
if(region == NTSC) {
|
||||
xml << " region='NTSC'";
|
||||
xml.append(" region='NTSC'");
|
||||
} else {
|
||||
xml << " region='PAL'";
|
||||
xml.append(" region='PAL'");
|
||||
}
|
||||
xml << ">\n";
|
||||
xml.append(">\n");
|
||||
|
||||
if(type == TypeSuperGameBoy1Bios) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <icd2 revision='1'>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </icd2>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <icd2 revision='1'>\n");
|
||||
xml.append(" <map address='00-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map address='80-bf:6000-7fff'/>\n");
|
||||
xml.append(" </icd2>\n");
|
||||
} else if(type == TypeSuperGameBoy2Bios) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <icd2 revision='2'>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </icd2>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <icd2 revision='2'>\n");
|
||||
xml.append(" <map address='00-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map address='80-bf:6000-7fff'/>\n");
|
||||
xml.append(" </icd2>\n");
|
||||
} else if(has_cx4) {
|
||||
xml.append(" <hitachidsp model='HG51B169' frequency='20000000' firmware='cx4.bin' sha256='ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18'>\n");
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map address='80-bf:6000-7fff'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
xml.append(" </hitachidsp>\n");
|
||||
} else if(has_spc7110) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-0f:8000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-cf:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='shadow' address='00-0f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='shadow' address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-cf:0000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
|
||||
xml << " <spc7110>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <map address='d0-ff:0000-ffff' offset='100000' size='" << hex(size - 0x100000) << "'/>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='30:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:4800-483f'/>\n";
|
||||
xml << " <map address='80-bf:4800-483f'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml.append(" <spc7110>\n");
|
||||
xml.append(" <mcu>\n");
|
||||
xml.append(" <map address='d0-ff:0000-ffff' offset='0x100000' size='0x", hex(size - 0x100000), "'/>\n");
|
||||
xml.append(" </mcu>\n");
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='00:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='30:6000-7fff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:4800-483f'/>\n");
|
||||
xml.append(" <map address='80-bf:4800-483f'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
if(has_spc7110rtc) {
|
||||
xml << " <rtc>\n";
|
||||
xml << " <map address='00-3f:4840-4842'/>\n";
|
||||
xml << " <map address='80-bf:4840-4842'/>\n";
|
||||
xml << " </rtc>\n";
|
||||
xml.append(" <rtc>\n");
|
||||
xml.append(" <map address='00-3f:4840-4842'/>\n");
|
||||
xml.append(" <map address='80-bf:4840-4842'/>\n");
|
||||
xml.append(" </rtc>\n");
|
||||
}
|
||||
xml << " <dcu>\n";
|
||||
xml << " <map address='50:0000-ffff'/>\n";
|
||||
xml << " </dcu>\n";
|
||||
xml << " </spc7110>\n";
|
||||
xml.append(" <dcu>\n");
|
||||
xml.append(" <map address='50:0000-ffff'/>\n");
|
||||
xml.append(" </dcu>\n");
|
||||
xml.append(" </spc7110>\n");
|
||||
} else if(mapper == LoROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='f0-ff:0000-7fff'/>\n");
|
||||
} else {
|
||||
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-ff:0000-ffff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='f0-ff:0000-ffff'/>\n");
|
||||
}
|
||||
xml << " </ram>\n";
|
||||
xml.append(" </ram>\n");
|
||||
}
|
||||
} else if(mapper == HiROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='shadow' address='00-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='40-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='shadow' address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-ff:0000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
|
||||
} else {
|
||||
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
|
||||
}
|
||||
xml << " </ram>\n";
|
||||
xml.append(" </ram>\n");
|
||||
}
|
||||
} else if(mapper == ExLoROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='40-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
}
|
||||
} else if(mapper == ExHiROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-3f:8000-ffff' offset='400000'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff' offset='400000'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff' offset='000000'/>\n";
|
||||
xml << " <map mode='linear' address='c0-ff:0000-ffff' offset='000000'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='shadow' address='00-3f:8000-ffff' offset='0x400000'/>\n");
|
||||
xml.append(" <map mode='linear' address='40-7f:0000-ffff' offset='0x400000'/>\n");
|
||||
xml.append(" <map mode='shadow' address='80-bf:8000-ffff' offset='0x000000'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-ff:0000-ffff' offset='0x000000'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
|
||||
} else {
|
||||
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
|
||||
}
|
||||
xml << " </ram>\n";
|
||||
xml.append(" </ram>\n");
|
||||
}
|
||||
} else if(mapper == SuperFXROM) {
|
||||
xml << " <superfx revision='2'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-5f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:6000-7fff' size='2000'/>\n";
|
||||
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:6000-7fff' size='2000'/>\n";
|
||||
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:3000-32ff'/>\n";
|
||||
xml << " <map address='80-bf:3000-32ff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </superfx>\n";
|
||||
xml.append(" <superfx revision='2'>\n");
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='40-5f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-df:0000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='00-3f:6000-7fff' size='0x2000'/>\n");
|
||||
xml.append(" <map mode='linear' address='60-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-bf:6000-7fff' size='0x2000'/>\n");
|
||||
xml.append(" <map mode='linear' address='e0-ff:0000-ffff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:3000-32ff'/>\n");
|
||||
xml.append(" <map address='80-bf:3000-32ff'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
xml.append(" </superfx>\n");
|
||||
} else if(mapper == SA1ROM) {
|
||||
xml << " <sa1>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='direct' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='direct' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='direct' address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram>\n";
|
||||
xml << " <map mode='direct' address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='direct' address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <iram size='800'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:3000-37ff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:3000-37ff'/>\n";
|
||||
xml << " </iram>\n";
|
||||
xml << " <bwram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='40-4f:0000-ffff'/>\n";
|
||||
xml << " </bwram>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:2200-23ff'/>\n";
|
||||
xml << " <map address='80-bf:2200-23ff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </sa1>\n";
|
||||
xml.append(" <sa1>\n");
|
||||
xml.append(" <mcu>\n");
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='direct' address='00-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='direct' address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='direct' address='c0-ff:0000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram>\n");
|
||||
xml.append(" <map mode='direct' address='00-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='direct' address='80-bf:6000-7fff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" </mcu>\n");
|
||||
xml.append(" <iram size='0x800'>\n");
|
||||
xml.append(" <map mode='linear' address='00-3f:3000-37ff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-bf:3000-37ff'/>\n");
|
||||
xml.append(" </iram>\n");
|
||||
xml.append(" <bwram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='40-4f:0000-ffff'/>\n");
|
||||
xml.append(" </bwram>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:2200-23ff'/>\n");
|
||||
xml.append(" <map address='80-bf:2200-23ff'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
xml.append(" </sa1>\n");
|
||||
} else if(mapper == BSCLoROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-1f:8000-ffff' offset='000000'/>\n";
|
||||
xml << " <map mode='linear' address='20-3f:8000-ffff' offset='100000'/>\n";
|
||||
xml << " <map mode='linear' address='80-9f:8000-ffff' offset='200000'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:8000-ffff' offset='100000'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <bsx>\n";
|
||||
xml << " <slot>\n";
|
||||
xml << " <map mode='linear' address='c0-ef:0000-ffff'/>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " </bsx>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-1f:8000-ffff' offset='0x000000'/>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:8000-ffff' offset='0x100000'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-9f:8000-ffff' offset='0x200000'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:8000-ffff' offset='0x100000'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='f0-ff:0000-7fff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" <bsx>\n");
|
||||
xml.append(" <slot>\n");
|
||||
xml.append(" <map mode='linear' address='c0-ef:0000-ffff'/>\n");
|
||||
xml.append(" </slot>\n");
|
||||
xml.append(" </bsx>\n");
|
||||
} else if(mapper == BSCHiROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-1f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-5f:0000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='80-9f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <bsx>\n";
|
||||
xml << " <slot>\n";
|
||||
xml << " <map mode='shadow' address='20-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='a0-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " </bsx>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='shadow' address='00-1f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='40-5f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='shadow' address='80-9f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-df:0000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" <bsx>\n");
|
||||
xml.append(" <slot>\n");
|
||||
xml.append(" <map mode='shadow' address='20-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='60-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map mode='shadow' address='a0-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='e0-ff:0000-ffff'/>\n");
|
||||
xml.append(" </slot>\n");
|
||||
xml.append(" </bsx>\n");
|
||||
} else if(mapper == BSXROM) {
|
||||
xml << " <bsx>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <map address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map address='40-7f:0000-ffff'/>\n";
|
||||
xml << " <map address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " <map address='20-3f:6000-7fff'/>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:5000-5fff'/>\n";
|
||||
xml << " <map address='80-bf:5000-5fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </bsx>\n";
|
||||
xml.append(" <bsx>\n");
|
||||
xml.append(" <mcu>\n");
|
||||
xml.append(" <map address='00-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map address='80-bf:8000-ffff'/>\n");
|
||||
xml.append(" <map address='40-7f:0000-ffff'/>\n");
|
||||
xml.append(" <map address='c0-ff:0000-ffff'/>\n");
|
||||
xml.append(" <map address='20-3f:6000-7fff'/>\n");
|
||||
xml.append(" </mcu>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:5000-5fff'/>\n");
|
||||
xml.append(" <map address='80-bf:5000-5fff'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
xml.append(" </bsx>\n");
|
||||
} else if(mapper == STROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-1f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-9f:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <sufamiturbo>\n";
|
||||
xml << " <slot id='A'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='20-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram>\n";
|
||||
xml << " <map mode='linear' address='60-63:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='e0-e3:8000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " <slot id='B'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='40-5f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram>\n";
|
||||
xml << " <map mode='linear' address='70-73:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-f3:8000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " </sufamiturbo>\n";
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='00-1f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='80-9f:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <sufamiturbo>\n");
|
||||
xml.append(" <slot id='A'>\n");
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='20-3f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='a0-bf:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram size='0x20000'>\n");
|
||||
xml.append(" <map mode='linear' address='60-63:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='e0-e3:8000-ffff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" </slot>\n");
|
||||
xml.append(" <slot id='B'>\n");
|
||||
xml.append(" <rom>\n");
|
||||
xml.append(" <map mode='linear' address='40-5f:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='c0-df:8000-ffff'/>\n");
|
||||
xml.append(" </rom>\n");
|
||||
xml.append(" <ram size='0x20000'>\n");
|
||||
xml.append(" <map mode='linear' address='70-73:8000-ffff'/>\n");
|
||||
xml.append(" <map mode='linear' address='f0-f3:8000-ffff'/>\n");
|
||||
xml.append(" </ram>\n");
|
||||
xml.append(" </slot>\n");
|
||||
xml.append(" </sufamiturbo>\n");
|
||||
}
|
||||
|
||||
if(has_srtc) {
|
||||
xml << " <srtc>\n";
|
||||
xml << " <map address='00-3f:2800-2801'/>\n";
|
||||
xml << " <map address='80-bf:2800-2801'/>\n";
|
||||
xml << " </srtc>\n";
|
||||
xml.append(" <srtc>\n");
|
||||
xml.append(" <map address='00-3f:2800-2801'/>\n");
|
||||
xml.append(" <map address='80-bf:2800-2801'/>\n");
|
||||
xml.append(" </srtc>\n");
|
||||
}
|
||||
|
||||
if(has_sdd1) {
|
||||
xml << " <sdd1>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <map address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:4800-4807'/>\n";
|
||||
xml << " <map address='80-bf:4800-4807'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </sdd1>\n";
|
||||
}
|
||||
|
||||
if(has_cx4) {
|
||||
xml << " <cx4>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </cx4>\n";
|
||||
xml.append(" <sdd1>\n");
|
||||
xml.append(" <mcu>\n");
|
||||
xml.append(" <map address='c0-ff:0000-ffff'/>\n");
|
||||
xml.append(" </mcu>\n");
|
||||
xml.append(" <mmio>\n");
|
||||
xml.append(" <map address='00-3f:4800-4807'/>\n");
|
||||
xml.append(" <map address='80-bf:4800-4807'/>\n");
|
||||
xml.append(" </mmio>\n");
|
||||
xml.append(" </sdd1>\n");
|
||||
}
|
||||
|
||||
if(has_dsp1) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
|
||||
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n");
|
||||
if(dsp1_mapper == DSP1LoROM1MB) {
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='20-3f:8000-bfff'/>\n");
|
||||
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='20-3f:c000-ffff'/>\n");
|
||||
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
} else if(dsp1_mapper == DSP1LoROM2MB) {
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60-6f:0000-3fff'/>\n";
|
||||
xml << " <map address='e0-ef:0000-3fff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='60-6f:4000-7fff'/>\n";
|
||||
xml << " <map address='e0-ef:4000-7fff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='60-6f:0000-3fff'/>\n");
|
||||
xml.append(" <map address='e0-ef:0000-3fff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='60-6f:4000-7fff'/>\n");
|
||||
xml.append(" <map address='e0-ef:4000-7fff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
} else if(dsp1_mapper == DSP1HiROM) {
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='00-1f:6000-6fff'/>\n";
|
||||
xml << " <map address='80-9f:6000-6fff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='00-1f:7000-7fff'/>\n";
|
||||
xml << " <map address='80-9f:7000-7fff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='00-1f:6000-6fff'/>\n");
|
||||
xml.append(" <map address='80-9f:6000-6fff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='00-1f:7000-7fff'/>\n");
|
||||
xml.append(" <map address='80-9f:7000-7fff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
}
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_dsp2) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n");
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='20-3f:8000-bfff'/>\n");
|
||||
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='20-3f:c000-ffff'/>\n");
|
||||
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_dsp3) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n");
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='20-3f:8000-bfff'/>\n");
|
||||
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='20-3f:c000-ffff'/>\n");
|
||||
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_dsp4) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='30-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='b0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='30-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='b0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n");
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='30-3f:8000-bfff'/>\n");
|
||||
xml.append(" <map address='b0-bf:8000-bfff'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='30-3f:c000-ffff'/>\n");
|
||||
xml.append(" <map address='b0-bf:c000-ffff'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_obc1) {
|
||||
xml << " <obc1>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </obc1>\n";
|
||||
xml.append(" <obc1>\n");
|
||||
xml.append(" <map address='00-3f:6000-7fff'/>\n");
|
||||
xml.append(" <map address='80-bf:6000-7fff'/>\n");
|
||||
xml.append(" </obc1>\n");
|
||||
}
|
||||
|
||||
if(has_st010) {
|
||||
xml << " <necdsp revision='upd96050' frequency='10000000' program='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60:0000'/>\n";
|
||||
xml << " <map address='e0:0000'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='60:0001'/>\n";
|
||||
xml << " <map address='e0:0001'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " <dp>\n";
|
||||
xml << " <map address='68-6f:0000-0fff'/>\n";
|
||||
xml << " <map address='e8-ef:0000-0fff'/>\n";
|
||||
xml << " </dp>\n";
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" <necdsp model='uPD96050' frequency='10000000' firmware='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n");
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='60:0000'/>\n");
|
||||
xml.append(" <map address='e0:0000'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='60:0001'/>\n");
|
||||
xml.append(" <map address='e0:0001'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
xml.append(" <dp>\n");
|
||||
xml.append(" <map address='68-6f:0000-0fff'/>\n");
|
||||
xml.append(" <map address='e8-ef:0000-0fff'/>\n");
|
||||
xml.append(" </dp>\n");
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_st011) {
|
||||
xml << " <necdsp revision='upd96050' frequency='15000000' program='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60:0000'/>\n";
|
||||
xml << " <map address='e0:0000'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='60:0001'/>\n";
|
||||
xml << " <map address='e0:0001'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " <dp>\n";
|
||||
xml << " <map address='68-6f:0000-0fff'/>\n";
|
||||
xml << " <map address='e8-ef:0000-0fff'/>\n";
|
||||
xml << " </dp>\n";
|
||||
xml << " </necdsp>\n";
|
||||
xml.append(" <necdsp model='uPD96050' frequency='15000000' firmware='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n");
|
||||
xml.append(" <dr>\n");
|
||||
xml.append(" <map address='60:0000'/>\n");
|
||||
xml.append(" <map address='e0:0000'/>\n");
|
||||
xml.append(" </dr>\n");
|
||||
xml.append(" <sr>\n");
|
||||
xml.append(" <map address='60:0001'/>\n");
|
||||
xml.append(" <map address='e0:0001'/>\n");
|
||||
xml.append(" </sr>\n");
|
||||
xml.append(" <dp>\n");
|
||||
xml.append(" <map address='68-6f:0000-0fff'/>\n");
|
||||
xml.append(" <map address='e8-ef:0000-0fff'/>\n");
|
||||
xml.append(" </dp>\n");
|
||||
xml.append(" </necdsp>\n");
|
||||
}
|
||||
|
||||
if(has_st018) {
|
||||
xml << " <setarisc program='ST-0018'>\n";
|
||||
xml << " <map address='00-3f:3800-38ff'/>\n";
|
||||
xml << " <map address='80-bf:3800-38ff'/>\n";
|
||||
xml << " </setarisc>\n";
|
||||
xml.append(" <setarisc firmware='ST-0018'>\n");
|
||||
xml.append(" <map address='00-3f:3800-38ff'/>\n");
|
||||
xml.append(" <map address='80-bf:3800-38ff'/>\n");
|
||||
xml.append(" </setarisc>\n");
|
||||
}
|
||||
|
||||
xml << "</cartridge>\n";
|
||||
xml.append("</cartridge>\n");
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
}
|
||||
|
||||
|
29
bsnes/nall/stack.hpp
Executable file
29
bsnes/nall/stack.hpp
Executable file
@@ -0,0 +1,29 @@
|
||||
#ifndef NALL_STACK_HPP
|
||||
#define NALL_STACK_HPP
|
||||
|
||||
#include <nall/concept.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
template<typename T> struct stack : public linear_vector<T> {
|
||||
void push(const T &value) {
|
||||
linear_vector<T>::append(value);
|
||||
}
|
||||
|
||||
T pull() {
|
||||
if(linear_vector<T>::size() == 0) throw;
|
||||
T value = linear_vector<T>::operator[](linear_vector<T>::size() - 1);
|
||||
linear_vector<T>::remove(linear_vector<T>::size() - 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
T& operator()() {
|
||||
if(linear_vector<T>::size() == 0) throw;
|
||||
return linear_vector<T>::operator[](linear_vector<T>::size() - 1);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct has_size<stack<T>> { enum { value = true }; };
|
||||
}
|
||||
|
||||
#endif
|
@@ -2,7 +2,9 @@
|
||||
#define NALL_STRING_HPP
|
||||
|
||||
#include <initializer_list>
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/sha256.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
#include <nall/string/base.hpp>
|
||||
|
@@ -6,29 +6,29 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <nall/concept.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/windows/utf8.hpp>
|
||||
|
||||
namespace nall {
|
||||
class string;
|
||||
template<typename T> inline string to_string(T);
|
||||
class lstring;
|
||||
template<typename T> inline const char* to_string(T);
|
||||
|
||||
class string {
|
||||
public:
|
||||
inline void reserve(unsigned);
|
||||
|
||||
inline string& assign(const char*);
|
||||
inline string& append(const char*);
|
||||
inline string& append(bool);
|
||||
inline string& append(signed int value);
|
||||
inline string& append(unsigned int value);
|
||||
inline string& append(double value);
|
||||
template<typename... Args> inline string& assign(Args&&... args);
|
||||
template<typename... Args> inline string& append(Args&&... args);
|
||||
|
||||
inline bool readfile(const char*);
|
||||
inline bool readfile(const string&);
|
||||
|
||||
inline string& replace (const char*, const char*);
|
||||
inline string& qreplace(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline string& replace(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline string& ireplace(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline string& qreplace(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline string& iqreplace(const char*, const char*);
|
||||
|
||||
inline unsigned length() const;
|
||||
|
||||
@@ -45,17 +45,18 @@ namespace nall {
|
||||
|
||||
inline string& lower();
|
||||
inline string& upper();
|
||||
inline string& qlower();
|
||||
inline string& qupper();
|
||||
inline string& transform(const char *before, const char *after);
|
||||
|
||||
template<unsigned limit = 0> inline string& ltrim(const char *key = " ");
|
||||
template<unsigned limit = 0> inline string& rtrim(const char *key = " ");
|
||||
template<unsigned limit = 0> inline string& trim (const char *key = " ");
|
||||
template<unsigned limit = 0> inline string& trim(const char *key = " ", const char *rkey = 0);
|
||||
|
||||
inline optional<unsigned> position(const char *key) const;
|
||||
inline optional<unsigned> iposition(const char *key) const;
|
||||
inline optional<unsigned> qposition(const char *key) const;
|
||||
|
||||
template<typename T> inline string& operator= (T value);
|
||||
template<typename T> inline string& operator<<(T value);
|
||||
inline optional<unsigned> iqposition(const char *key) const;
|
||||
|
||||
inline operator const char*() const;
|
||||
inline char* operator()();
|
||||
@@ -76,10 +77,16 @@ namespace nall {
|
||||
inline string(string&&);
|
||||
inline ~string();
|
||||
|
||||
//internal functions
|
||||
inline string& assign_(const char*);
|
||||
inline string& append_(const char*);
|
||||
|
||||
protected:
|
||||
char *data;
|
||||
unsigned size;
|
||||
|
||||
template<unsigned Limit, bool Insensitive, bool Quoted> inline string& ureplace(const char*, const char*);
|
||||
|
||||
#if defined(QSTRING_H)
|
||||
public:
|
||||
inline operator QString() const;
|
||||
@@ -91,36 +98,43 @@ namespace nall {
|
||||
template<typename T> inline lstring& operator<<(T value);
|
||||
|
||||
inline optional<unsigned> find(const char*) const;
|
||||
template<unsigned limit = 0> inline void split (const char*, const char*);
|
||||
template<unsigned limit = 0> inline void qsplit(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline lstring& split(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline lstring& isplit(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline lstring& qsplit(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline lstring& iqsplit(const char*, const char*);
|
||||
|
||||
lstring();
|
||||
lstring(std::initializer_list<string>);
|
||||
|
||||
protected:
|
||||
template<unsigned Limit, bool Insensitive, bool Quoted> inline lstring& usplit(const char*, const char*);
|
||||
};
|
||||
|
||||
//compare.hpp
|
||||
inline char chrlower(char c);
|
||||
inline char chrupper(char c);
|
||||
inline int stricmp(const char *str1, const char *str2);
|
||||
inline int istrcmp(const char *str1, const char *str2);
|
||||
inline bool wildcard(const char *str, const char *pattern);
|
||||
inline bool iwildcard(const char *str, const char *pattern);
|
||||
inline bool strbegin (const char *str, const char *key);
|
||||
inline bool stribegin(const char *str, const char *key);
|
||||
inline bool strend (const char *str, const char *key);
|
||||
inline bool striend(const char *str, const char *key);
|
||||
inline bool strbegin(const char *str, const char *key);
|
||||
inline bool istrbegin(const char *str, const char *key);
|
||||
inline bool strend(const char *str, const char *key);
|
||||
inline bool istrend(const char *str, const char *key);
|
||||
|
||||
//convert.hpp
|
||||
inline char* strlower(char *str);
|
||||
inline char* strupper(char *str);
|
||||
inline char* qstrlower(char *str);
|
||||
inline char* qstrupper(char *str);
|
||||
inline char* strtr(char *dest, const char *before, const char *after);
|
||||
inline uintmax_t hex (const char *str);
|
||||
inline intmax_t integer(const char *str);
|
||||
inline uintmax_t hex(const char *str);
|
||||
inline intmax_t integer(const char *str);
|
||||
inline uintmax_t decimal(const char *str);
|
||||
inline uintmax_t binary (const char *str);
|
||||
inline double fp (const char *str);
|
||||
inline uintmax_t binary(const char *str);
|
||||
inline double fp(const char *str);
|
||||
|
||||
//math.hpp
|
||||
inline bool strint (const char *str, int &result);
|
||||
inline bool strint(const char *str, int &result);
|
||||
inline bool strmath(const char *str, int &result);
|
||||
|
||||
//platform.hpp
|
||||
@@ -134,26 +148,31 @@ namespace nall {
|
||||
|
||||
//strpos.hpp
|
||||
inline optional<unsigned> strpos(const char *str, const char *key);
|
||||
inline optional<unsigned> istrpos(const char *str, const char *key);
|
||||
inline optional<unsigned> qstrpos(const char *str, const char *key);
|
||||
inline optional<unsigned> iqstrpos(const char *str, const char *key);
|
||||
template<bool Insensitive = false, bool Quoted = false> inline optional<unsigned> ustrpos(const char *str, const char *key);
|
||||
|
||||
//trim.hpp
|
||||
template<unsigned limit = 0> inline char* ltrim(char *str, const char *key = " ");
|
||||
template<unsigned limit = 0> inline char* rtrim(char *str, const char *key = " ");
|
||||
template<unsigned limit = 0> inline char* trim (char *str, const char *key = " ");
|
||||
template<unsigned limit = 0> inline char* trim(char *str, const char *key = " ", const char *rkey = 0);
|
||||
|
||||
//utility.hpp
|
||||
template<bool Insensitive> alwaysinline bool chrequal(char x, char y);
|
||||
template<bool Quoted, typename T> alwaysinline bool quoteskip(T *&p);
|
||||
template<bool Quoted, typename T> alwaysinline bool quotecopy(char *&t, T *&p);
|
||||
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
|
||||
inline unsigned strlcat(string &dest, const char *src, unsigned length);
|
||||
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
|
||||
inline string substr(const char *src, unsigned start = 0, unsigned length = ~0u);
|
||||
inline string sha256(const uint8_t *data, unsigned size);
|
||||
|
||||
inline string integer(intmax_t value);
|
||||
template<unsigned length = 0> inline string linteger(intmax_t value);
|
||||
template<unsigned length = 0> inline string rinteger(intmax_t value);
|
||||
inline string decimal(uintmax_t value);
|
||||
template<unsigned length = 0> inline string ldecimal(uintmax_t value);
|
||||
template<unsigned length = 0> inline string rdecimal(uintmax_t value);
|
||||
template<unsigned length = 0> inline string hex(uintmax_t value);
|
||||
template<unsigned length = 0> inline string binary(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = ' '> inline string integer(intmax_t value);
|
||||
template<unsigned length = 0, char padding = ' '> inline string linteger(intmax_t value);
|
||||
template<unsigned length = 0, char padding = ' '> inline string decimal(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = ' '> inline string ldecimal(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string hex(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string binary(uintmax_t value);
|
||||
inline unsigned fp(char *str, double value);
|
||||
inline string fp(double value);
|
||||
|
||||
|
@@ -4,17 +4,16 @@
|
||||
namespace nall {
|
||||
|
||||
//this is needed, as C++0x does not support explicit template specialization inside classes
|
||||
template<> inline string to_string<bool> (bool v) { return v ? "true" : "false"; }
|
||||
template<> inline string to_string<signed int> (signed int v) { return integer(v); }
|
||||
template<> inline string to_string<unsigned int> (unsigned int v) { return decimal(v); }
|
||||
template<> inline string to_string<double> (double v) { return fp(v); }
|
||||
template<> inline string to_string<char*> (char *v) { return v; }
|
||||
template<> inline string to_string<const char*> (const char *v) { return v; }
|
||||
template<> inline string to_string<string> (string v) { return v; }
|
||||
template<> inline string to_string<const string&>(const string &v) { return v; }
|
||||
|
||||
template<typename T> string& string::operator= (T value) { return assign(to_string<T>(value)); }
|
||||
template<typename T> string& string::operator<<(T value) { return append(to_string<T>(value)); }
|
||||
template<> inline const char* to_string<bool> (bool v) { return v ? "true" : "false"; }
|
||||
template<> inline const char* to_string<signed int> (signed int v) { static char temp[256]; snprintf(temp, 255, "%+d", v); return temp; }
|
||||
template<> inline const char* to_string<unsigned int> (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; }
|
||||
template<> inline const char* to_string<intmax_t> (intmax_t v) { static char temp[256]; snprintf(temp, 255, "%+lld", (long long)v); return temp; }
|
||||
template<> inline const char* to_string<uintmax_t> (uintmax_t v) { static char temp[256]; snprintf(temp, 255, "%llu", (unsigned long long)v); return temp; }
|
||||
template<> inline const char* to_string<double> (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
|
||||
template<> inline const char* to_string<char*> (char *v) { return v; }
|
||||
template<> inline const char* to_string<const char*> (const char *v) { return v; }
|
||||
template<> inline const char* to_string<string> (string v) { return v; }
|
||||
template<> inline const char* to_string<const string&>(const string &v) { return v; }
|
||||
|
||||
template<typename T> lstring& lstring::operator<<(T value) {
|
||||
operator[](size()).assign(to_string<T>(value));
|
||||
@@ -22,8 +21,8 @@ template<typename T> lstring& lstring::operator<<(T value) {
|
||||
}
|
||||
|
||||
#if defined(QSTRING_H)
|
||||
template<> inline string to_string<QString>(QString v) { return v.toUtf8().constData(); }
|
||||
template<> inline string to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
|
||||
template<> inline const char* to_string<QString>(QString v) { return v.toUtf8().constData(); }
|
||||
template<> inline const char* to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
|
||||
string::operator QString() const { return QString::fromUtf8(*this); }
|
||||
#endif
|
||||
|
||||
|
@@ -11,7 +11,7 @@ char chrupper(char c) {
|
||||
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
int stricmp(const char *str1, const char *str2) {
|
||||
int istrcmp(const char *str1, const char *str2) {
|
||||
while(*str1) {
|
||||
if(chrlower(*str1) != chrlower(*str2)) break;
|
||||
str1++, str2++;
|
||||
@@ -66,7 +66,7 @@ bool strbegin(const char *str, const char *key) {
|
||||
return (!memcmp(str, key, ksl));
|
||||
}
|
||||
|
||||
bool stribegin(const char *str, const char *key) {
|
||||
bool istrbegin(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
||||
if(ksl > ssl) return false;
|
||||
@@ -89,7 +89,7 @@ bool strend(const char *str, const char *key) {
|
||||
return (!memcmp(str + ssl - ksl, key, ksl));
|
||||
}
|
||||
|
||||
bool striend(const char *str, const char *key) {
|
||||
bool istrend(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
||||
if(ksl > ssl) return false;
|
||||
|
@@ -23,6 +23,26 @@ char* strupper(char *str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
char* qstrlower(char *s) {
|
||||
if(!s) return 0;
|
||||
bool quoted = false;
|
||||
while(*s) {
|
||||
if(*s == '\"' || *s == '\'') quoted ^= 1;
|
||||
if(quoted == false && *s >= 'A' && *s <= 'Z') *s += 0x20;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
char* qstrupper(char *s) {
|
||||
if(!s) return 0;
|
||||
bool quoted = false;
|
||||
while(*s) {
|
||||
if(*s == '\"' || *s == '\'') quoted ^= 1;
|
||||
if(quoted == false && *s >= 'a' && *s <= 'z') *s -= 0x20;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
char* strtr(char *dest, const char *before, const char *after) {
|
||||
if(!dest || !before || !after) return dest;
|
||||
int sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
||||
@@ -65,8 +85,11 @@ intmax_t integer(const char *str) {
|
||||
intmax_t result = 0;
|
||||
bool negate = false;
|
||||
|
||||
//check for negation
|
||||
if(*str == '-') {
|
||||
//check for sign
|
||||
if(*str == '+') {
|
||||
negate = false;
|
||||
str++;
|
||||
} else if(*str == '-') {
|
||||
negate = true;
|
||||
str++;
|
||||
}
|
||||
@@ -114,38 +137,7 @@ uintmax_t binary(const char *str) {
|
||||
}
|
||||
|
||||
double fp(const char *str) {
|
||||
if(!str) return 0.0;
|
||||
bool negate = false;
|
||||
|
||||
//check for negation
|
||||
if(*str == '-') {
|
||||
negate = true;
|
||||
str++;
|
||||
}
|
||||
|
||||
intmax_t result_integral = 0;
|
||||
while(*str) {
|
||||
uint8_t x = *str++;
|
||||
if(x >= '0' && x <= '9') x -= '0';
|
||||
else if(x == '.' || x == ',') break; //break loop and read fractional part
|
||||
else return (double)result_integral; //invalid value, assume no fractional part
|
||||
result_integral = result_integral * 10 + x;
|
||||
}
|
||||
|
||||
intmax_t result_fractional = 0;
|
||||
while(*str) {
|
||||
uint8_t x = *str++;
|
||||
if(x >= '0' && x <= '9') x -= '0';
|
||||
else break; //stop at first invalid character
|
||||
result_fractional = result_fractional * 10 + x;
|
||||
}
|
||||
|
||||
//calculate fractional portion
|
||||
double result = (double)result_fractional;
|
||||
while((uintmax_t)result > 0) result /= 10.0;
|
||||
result += (double)result_integral;
|
||||
|
||||
return !negate ? result : -result;
|
||||
return atof(str);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,6 +3,15 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
static void istring(string &output) {
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
static void istring(string &output, const T &value, Args&&... args) {
|
||||
output.append_(to_string(value));
|
||||
istring(output, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void string::reserve(unsigned size_) {
|
||||
if(size_ > size) {
|
||||
size = size_;
|
||||
@@ -11,25 +20,31 @@ void string::reserve(unsigned size_) {
|
||||
}
|
||||
}
|
||||
|
||||
string& string::assign(const char *s) {
|
||||
template<typename... Args> string& string::assign(Args&&... args) {
|
||||
*data = 0;
|
||||
istring(*this, std::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... Args> string& string::append(Args&&... args) {
|
||||
istring(*this, std::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::assign_(const char *s) {
|
||||
unsigned length = strlen(s);
|
||||
reserve(length);
|
||||
strcpy(data, s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::append(const char *s) {
|
||||
string& string::append_(const char *s) {
|
||||
unsigned length = strlen(data) + strlen(s);
|
||||
reserve(length);
|
||||
strcat(data, s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::append(bool value) { append(value ? "true" : "false"); return *this; }
|
||||
string& string::append(signed int value) { append(integer(value)); return *this; }
|
||||
string& string::append(unsigned int value) { append(decimal(value)); return *this; }
|
||||
string& string::append(double value) { append(fp(value)); return *this; }
|
||||
|
||||
string::operator const char*() const {
|
||||
return data;
|
||||
}
|
||||
@@ -64,15 +79,6 @@ string& string::operator=(string &&source) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
static void istring(string &output) {
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
static void istring(string &output, const T &value, Args&&... args) {
|
||||
output.append(value);
|
||||
istring(output, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args> string::string(Args&&... args) {
|
||||
size = 64;
|
||||
data = (char*)malloc(size + 1);
|
||||
@@ -95,7 +101,7 @@ string::~string() {
|
||||
if(data) free(data);
|
||||
}
|
||||
|
||||
bool string::readfile(const char *filename) {
|
||||
bool string::readfile(const string &filename) {
|
||||
assign("");
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
@@ -3,6 +3,8 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
static function<int64_t (const char *&)> eval_fallback;
|
||||
|
||||
static int eval_integer(const char *&s) {
|
||||
if(!*s) throw "unrecognized_integer";
|
||||
int value = 0, x = *s, y = *(s + 1);
|
||||
@@ -58,7 +60,7 @@ static int eval_integer(const char *&s) {
|
||||
}
|
||||
|
||||
static int eval(const char *&s, int depth = 0) {
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
if(!*s) throw "unrecognized_token";
|
||||
int value = 0, x = *s, y = *(s + 1);
|
||||
|
||||
@@ -74,10 +76,12 @@ static int eval(const char *&s, int depth = 0) {
|
||||
|
||||
else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s);
|
||||
|
||||
else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing
|
||||
|
||||
else throw "unrecognized_token";
|
||||
|
||||
while(true) {
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
if(!*s) break;
|
||||
x = *s, y = *(s + 1);
|
||||
|
||||
|
@@ -3,15 +3,15 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
string realpath(const char *name) {
|
||||
string currentpath() {
|
||||
char path[PATH_MAX];
|
||||
if(::realpath(name, path)) {
|
||||
if(::getcwd(path)) {
|
||||
string result(path);
|
||||
result.transform("\\", "/");
|
||||
if(result.endswith("/") == false) result.append("/");
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
return "./";
|
||||
}
|
||||
|
||||
string userpath() {
|
||||
@@ -22,18 +22,17 @@ string userpath() {
|
||||
if(result.endswith("/") == false) result.append("/");
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
return currentpath();
|
||||
}
|
||||
|
||||
string currentpath() {
|
||||
string realpath(const char *name) {
|
||||
char path[PATH_MAX];
|
||||
if(::getcwd(path)) {
|
||||
if(::realpath(name, path)) {
|
||||
string result(path);
|
||||
result.transform("\\", "/");
|
||||
if(result.endswith("/") == false) result.append("/");
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
return userpath();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,100 +3,49 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
string& string::replace(const char *key, const char *token) {
|
||||
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = length();
|
||||
unsigned int replace_count = 0, size = ssl;
|
||||
char *buffer;
|
||||
template<unsigned Limit, bool Insensitive, bool Quoted>
|
||||
string& string::ureplace(const char *key, const char *token) {
|
||||
if(!key || !*key) return *this;
|
||||
enum : unsigned { limit = Limit ? Limit : ~0u };
|
||||
|
||||
if(ksl <= ssl) {
|
||||
if(tsl > ksl) { //the new string may be longer than the old string...
|
||||
for(i = 0; i <= ssl - ksl;) { //so let's find out how big of a string we'll need...
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
replace_count++;
|
||||
i += ksl;
|
||||
} else i++;
|
||||
}
|
||||
size = ssl + ((tsl - ksl) * replace_count);
|
||||
reserve(size);
|
||||
const char *p = data;
|
||||
unsigned counter = 0, keyLength = 0;
|
||||
|
||||
while(*p) {
|
||||
if(quoteskip<Quoted>(p)) continue;
|
||||
for(unsigned n = 0;; n++) {
|
||||
if(key[n] == 0) { counter++; p += n; keyLength = n; break; }
|
||||
if(!chrequal<Insensitive>(key[n], p[n])) { p++; break; }
|
||||
}
|
||||
|
||||
buffer = new char[size + 1];
|
||||
for(i = z = 0; i < ssl;) {
|
||||
if(i <= ssl - ksl) {
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
memcpy(buffer + z, token, tsl);
|
||||
z += tsl;
|
||||
i += ksl;
|
||||
} else buffer[z++] = data[i++];
|
||||
} else buffer[z++] = data[i++];
|
||||
}
|
||||
buffer[z] = 0;
|
||||
|
||||
assign(buffer);
|
||||
delete[] buffer;
|
||||
}
|
||||
if(counter == 0) return *this;
|
||||
if(Limit) counter = min(counter, Limit);
|
||||
|
||||
char *t = data, *base;
|
||||
unsigned tokenLength = strlen(token);
|
||||
if(tokenLength > keyLength) {
|
||||
t = base = strdup(data);
|
||||
reserve((unsigned)(p - data) + ((tokenLength - keyLength) * counter));
|
||||
}
|
||||
char *o = data;
|
||||
|
||||
while(*t && counter) {
|
||||
if(quotecopy<Quoted>(o, t)) continue;
|
||||
for(unsigned n = 0;; n++) {
|
||||
if(key[n] == 0) { counter--; memcpy(o, token, tokenLength); t += keyLength; o += tokenLength; break; }
|
||||
if(!chrequal<Insensitive>(key[n], t[n])) { *o++ = *t++; break; }
|
||||
}
|
||||
}
|
||||
do *o++ = *t; while(*t++);
|
||||
if(tokenLength > keyLength) free(base);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::qreplace(const char *key, const char *token) {
|
||||
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = length();
|
||||
unsigned int replace_count = 0, size = ssl;
|
||||
uint8_t x;
|
||||
char *buffer;
|
||||
|
||||
if(ksl <= ssl) {
|
||||
if(tsl > ksl) {
|
||||
for(i = 0; i <= ssl - ksl;) {
|
||||
x = data[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
l = i;
|
||||
i++;
|
||||
while(data[i++] != x) {
|
||||
if(i == ssl) {
|
||||
i = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
replace_count++;
|
||||
i += ksl;
|
||||
} else i++;
|
||||
}
|
||||
size = ssl + ((tsl - ksl) * replace_count);
|
||||
reserve(size);
|
||||
}
|
||||
|
||||
buffer = new char[size + 1];
|
||||
for(i = z = 0; i < ssl;) {
|
||||
x = data[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
l = i++;
|
||||
while(data[i] != x && i < ssl)i++;
|
||||
if(i >= ssl)i = l;
|
||||
else {
|
||||
memcpy(buffer + z, data + l, i - l);
|
||||
z += i - l;
|
||||
}
|
||||
}
|
||||
if(i <= ssl - ksl) {
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
memcpy(buffer + z, token, tsl);
|
||||
z += tsl;
|
||||
i += ksl;
|
||||
replace_count++;
|
||||
} else buffer[z++] = data[i++];
|
||||
} else buffer[z++] = data[i++];
|
||||
}
|
||||
buffer[z] = 0;
|
||||
|
||||
assign(buffer);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
template<unsigned Limit> string &string::replace(const char *key, const char *token) { return ureplace<Limit, false, false>(key, token); }
|
||||
template<unsigned Limit> string &string::ireplace(const char *key, const char *token) { return ureplace<Limit, true, false>(key, token); }
|
||||
template<unsigned Limit> string &string::qreplace(const char *key, const char *token) { return ureplace<Limit, false, true>(key, token); }
|
||||
template<unsigned Limit> string &string::iqreplace(const char *key, const char *token) { return ureplace<Limit, true, true>(key, token); }
|
||||
|
||||
};
|
||||
|
||||
|
@@ -3,56 +3,36 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<unsigned Limit> void lstring::split(const char *key, const char *src) {
|
||||
unsigned limit = Limit;
|
||||
template<unsigned Limit, bool Insensitive, bool Quoted> lstring& lstring::usplit(const char *key, const char *base) {
|
||||
reset();
|
||||
if(!key || !*key) return *this;
|
||||
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
int lp = 0, split_count = 0;
|
||||
const char *p = base;
|
||||
unsigned counter = 0;
|
||||
|
||||
for(int i = 0; i <= ssl - ksl;) {
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
strlcpy(operator[](split_count++), src + lp, i - lp + 1);
|
||||
i += ksl;
|
||||
lp = i;
|
||||
if(!--limit) break;
|
||||
} else i++;
|
||||
}
|
||||
|
||||
operator[](split_count++) = src + lp;
|
||||
}
|
||||
|
||||
template<unsigned Limit> void lstring::qsplit(const char *key, const char *src) {
|
||||
unsigned limit = Limit;
|
||||
reset();
|
||||
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
int lp = 0, split_count = 0;
|
||||
|
||||
for(int i = 0; i <= ssl - ksl;) {
|
||||
uint8_t x = src[i];
|
||||
|
||||
if(x == '\"' || x == '\'') {
|
||||
int z = i++; //skip opening quote
|
||||
while(i < ssl && src[i] != x) i++;
|
||||
if(i >= ssl) i = z; //failed match, rewind i
|
||||
else {
|
||||
i++; //skip closing quote
|
||||
continue; //restart in case next char is also a quote
|
||||
while(*p) {
|
||||
if(Limit) if(counter >= Limit) break;
|
||||
if(quoteskip<Quoted>(p)) continue;
|
||||
for(unsigned n = 0;; n++) {
|
||||
if(key[n] == 0) {
|
||||
strlcpy(operator[](counter++), base, (unsigned)(p - base + 1));
|
||||
p += n;
|
||||
base = p;
|
||||
break;
|
||||
}
|
||||
if(!chrequal<Insensitive>(key[n], p[n])) { p++; break; }
|
||||
}
|
||||
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
strlcpy(operator[](split_count++), src + lp, i - lp + 1);
|
||||
i += ksl;
|
||||
lp = i;
|
||||
if(!--limit) break;
|
||||
} else i++;
|
||||
}
|
||||
|
||||
operator[](split_count++) = src + lp;
|
||||
operator[](counter) = base;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned Limit> lstring& lstring::split(const char *key, const char *src) { return usplit<Limit, false, false>(key, src); }
|
||||
template<unsigned Limit> lstring& lstring::isplit(const char *key, const char *src) { return usplit<Limit, true, false>(key, src); }
|
||||
template<unsigned Limit> lstring& lstring::qsplit(const char *key, const char *src) { return usplit<Limit, false, true>(key, src); }
|
||||
template<unsigned Limit> lstring& lstring::iqsplit(const char *key, const char *src) { return usplit<Limit, true, true>(key, src); }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -2,40 +2,33 @@
|
||||
#define NALL_STRING_STRPOS_HPP
|
||||
|
||||
//usage example:
|
||||
//if(auto pos = strpos(str, key)) print(pos(), "\n");
|
||||
//prints position of key within str, only if it is found
|
||||
//if(auto position = strpos(str, key)) print(position(), "\n");
|
||||
//prints position of key within str; but only if it is found
|
||||
|
||||
namespace nall {
|
||||
|
||||
optional<unsigned> strpos(const char *str, const char *key) {
|
||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl) return { false, 0 };
|
||||
template<bool Insensitive, bool Quoted>
|
||||
optional<unsigned> ustrpos(const char *str, const char *key) {
|
||||
const char *base = str;
|
||||
|
||||
for(unsigned i = 0; i <= ssl - ksl; i++) {
|
||||
if(!memcmp(str + i, key, ksl)) return { true, i };
|
||||
}
|
||||
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
optional<unsigned> qstrpos(const char *str, const char *key) {
|
||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl) return { false, 0 };
|
||||
|
||||
for(unsigned i = 0; i <= ssl - ksl;) {
|
||||
uint8_t x = str[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
uint8_t z = i++;
|
||||
while(str[i] != x && i < ssl) i++;
|
||||
if(i >= ssl) i = z;
|
||||
while(*str) {
|
||||
if(quoteskip<Quoted>(str)) continue;
|
||||
for(unsigned n = 0;; n++) {
|
||||
if(key[n] == 0) return { true, (unsigned)(str - base) };
|
||||
if(str[n] == 0) return { false, 0 };
|
||||
if(!chrequal<Insensitive>(str[n], key[n])) break;
|
||||
}
|
||||
if(!memcmp(str + i, key, ksl)) return { true, i };
|
||||
i++;
|
||||
str++;
|
||||
}
|
||||
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
optional<unsigned> strpos(const char *str, const char *key) { return ustrpos<false, false>(str, key); }
|
||||
optional<unsigned> istrpos(const char *str, const char *key) { return ustrpos<true, false>(str, key); }
|
||||
optional<unsigned> qstrpos(const char *str, const char *key) { return ustrpos<false, true>(str, key); }
|
||||
optional<unsigned> iqstrpos(const char *str, const char *key) { return ustrpos<true, true>(str, key); }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -29,7 +29,8 @@ template<unsigned Limit> char* rtrim(char *str, const char *key) {
|
||||
return str;
|
||||
}
|
||||
|
||||
template<unsigned limit> char* trim(char *str, const char *key) {
|
||||
template<unsigned limit> char* trim(char *str, const char *key, const char *rkey) {
|
||||
if(rkey) return ltrim<limit>(rtrim<limit>(str, rkey), key);
|
||||
return ltrim<limit>(rtrim<limit>(str, key), key);
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,38 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<bool Insensitive>
|
||||
bool chrequal(char x, char y) {
|
||||
if(Insensitive) return chrlower(x) == chrlower(y);
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template<bool Quoted, typename T>
|
||||
bool quoteskip(T *&p) {
|
||||
if(Quoted == false) return false;
|
||||
if(*p != '\'' && *p != '\"') return false;
|
||||
|
||||
while(*p == '\'' || *p == '\"') {
|
||||
char x = *p++;
|
||||
while(*p && *p++ != x);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool Quoted, typename T>
|
||||
bool quotecopy(char *&t, T *&p) {
|
||||
if(Quoted == false) return false;
|
||||
if(*p != '\'' && *p != '\"') return false;
|
||||
|
||||
while(*p == '\'' || *p == '\"') {
|
||||
char x = *p++;
|
||||
*t++ = x;
|
||||
while(*p && *p != x) *t++ = *p++;
|
||||
*t++ = *p++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned strlcpy(string &dest, const char *src, unsigned length) {
|
||||
dest.reserve(length);
|
||||
return strlcpy(dest(), src, length);
|
||||
@@ -15,7 +47,7 @@ unsigned strlcat(string &dest, const char *src, unsigned length) {
|
||||
|
||||
string substr(const char *src, unsigned start, unsigned length) {
|
||||
string dest;
|
||||
if(length == 0) {
|
||||
if(length == ~0u) {
|
||||
//copy entire string
|
||||
dest = src + start;
|
||||
} else {
|
||||
@@ -25,35 +57,21 @@ string substr(const char *src, unsigned start, unsigned length) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
string sha256(const uint8_t *data, unsigned size) {
|
||||
sha256_ctx sha;
|
||||
uint8_t hash[32];
|
||||
sha256_init(&sha);
|
||||
sha256_chunk(&sha, data, size);
|
||||
sha256_final(&sha);
|
||||
sha256_hash(&sha, hash);
|
||||
string result;
|
||||
foreach(byte, hash) result.append(hex<2>(byte));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* arithmetic <> string */
|
||||
|
||||
string integer(intmax_t value) {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value % 10;
|
||||
buffer[size++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
buffer[size++] = negative ? '-' : '+';
|
||||
buffer[size] = 0;
|
||||
|
||||
char result[size + 1];
|
||||
memset(result, '0', size);
|
||||
result[size] = 0;
|
||||
|
||||
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<unsigned length> string linteger(intmax_t value) {
|
||||
template<unsigned length_, char padding> string integer(intmax_t value) {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
@@ -68,66 +86,22 @@ template<unsigned length> string linteger(intmax_t value) {
|
||||
buffer[size++] = negative ? '-' : '+';
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<unsigned length> string rinteger(intmax_t value) {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value % 10;
|
||||
buffer[size++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
buffer[size++] = negative ? '-' : '+';
|
||||
buffer[size] = 0;
|
||||
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return result;
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
string decimal(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value % 10;
|
||||
buffer[size++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
buffer[size] = 0;
|
||||
|
||||
char result[size + 1];
|
||||
memset(result, '0', size);
|
||||
result[size] = 0;
|
||||
|
||||
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<unsigned length> string ldecimal(uintmax_t value) {
|
||||
template<unsigned length_, char padding> string linteger(intmax_t value) {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
@@ -136,20 +110,22 @@ template<unsigned length> string ldecimal(uintmax_t value) {
|
||||
buffer[size++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
buffer[size++] = negative ? '-' : '+';
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return result;
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length> string rdecimal(uintmax_t value) {
|
||||
template<unsigned length_, char padding> string decimal(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
@@ -160,61 +136,83 @@ template<unsigned length> string rdecimal(uintmax_t value) {
|
||||
} while(value);
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return result;
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length> string hex(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
template<unsigned length_, char padding> string ldecimal(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value % 10;
|
||||
buffer[size++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length_, char padding> string hex(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
//render string backwards, as we do not know its length yet
|
||||
do {
|
||||
unsigned n = value & 15;
|
||||
output[offset++] = n < 10 ? '0' + n : 'a' + n - 10;
|
||||
buffer[size++] = n < 10 ? '0' + n : 'a' + n - 10;
|
||||
value >>= 4;
|
||||
} while(value);
|
||||
|
||||
while(offset < length) output[offset++] = '0';
|
||||
output[offset--] = 0;
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
//reverse the string in-place
|
||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
||||
char temp = output[i];
|
||||
output[i] = output[offset - i];
|
||||
output[offset - i] = temp;
|
||||
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return output;
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
template<unsigned length> string binary(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
template<unsigned length_, char padding> string binary(uintmax_t value) {
|
||||
char buffer[256];
|
||||
unsigned size = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value & 1;
|
||||
output[offset++] = '0' + n;
|
||||
buffer[size++] = '0' + n;
|
||||
value >>= 1;
|
||||
} while(value);
|
||||
|
||||
while(offset < length) output[offset++] = '0';
|
||||
output[offset--] = 0;
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, padding, length);
|
||||
result[length] = 0;
|
||||
|
||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
||||
char temp = output[i];
|
||||
output[i] = output[offset - i];
|
||||
output[offset - i] = temp;
|
||||
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return output;
|
||||
return (const char*)result;
|
||||
}
|
||||
|
||||
//using sprintf is certainly not the most ideal method to convert
|
||||
|
@@ -6,27 +6,31 @@ namespace nall {
|
||||
unsigned string::length() const { return strlen(data); }
|
||||
|
||||
bool string::equals(const char *str) const { return !strcmp(data, str); }
|
||||
bool string::iequals(const char *str) const { return !stricmp(data, str); }
|
||||
bool string::iequals(const char *str) const { return !istrcmp(data, str); }
|
||||
|
||||
bool string::wildcard(const char *str) const { return nall::wildcard(data, str); }
|
||||
bool string::iwildcard(const char *str) const { return nall::iwildcard(data, str); }
|
||||
|
||||
bool string::beginswith(const char *str) const { return strbegin(data, str); }
|
||||
bool string::ibeginswith(const char *str) const { return stribegin(data, str); }
|
||||
bool string::ibeginswith(const char *str) const { return istrbegin(data, str); }
|
||||
|
||||
bool string::endswith(const char *str) const { return strend(data, str); }
|
||||
bool string::iendswith(const char *str) const { return striend(data, str); }
|
||||
bool string::iendswith(const char *str) const { return istrend(data, str); }
|
||||
|
||||
string& string::lower() { nall::strlower(data); return *this; }
|
||||
string& string::upper() { nall::strupper(data); return *this; }
|
||||
string& string::qlower() { nall::qstrlower(data); return *this; }
|
||||
string& string::qupper() { nall::qstrupper(data); return *this; }
|
||||
string& string::transform(const char *before, const char *after) { nall::strtr(data, before, after); return *this; }
|
||||
|
||||
template<unsigned limit> string& string::ltrim(const char *key) { nall::ltrim<limit>(data, key); return *this; }
|
||||
template<unsigned limit> string& string::rtrim(const char *key) { nall::rtrim<limit>(data, key); return *this; }
|
||||
template<unsigned limit> string& string::trim (const char *key) { nall::trim <limit>(data, key); return *this; }
|
||||
template<unsigned limit> string& string::trim(const char *key, const char *rkey) { nall::trim <limit>(data, key, rkey); return *this; }
|
||||
|
||||
optional<unsigned> string::position(const char *key) const { return strpos(data, key); }
|
||||
optional<unsigned> string::iposition(const char *key) const { return istrpos(data, key); }
|
||||
optional<unsigned> string::qposition(const char *key) const { return qstrpos(data, key); }
|
||||
optional<unsigned> string::iqposition(const char *key) const { return iqstrpos(data, key); }
|
||||
|
||||
}
|
||||
|
||||
|
@@ -77,7 +77,7 @@ inline string xml_element::parse() const {
|
||||
if(auto pos = strpos(source, "]]>")) {
|
||||
if(pos() - 9 > 0) {
|
||||
string cdata = substr(source, 9, pos() - 9);
|
||||
data << cdata;
|
||||
data.append(cdata);
|
||||
offset += strlen(cdata);
|
||||
}
|
||||
source += 9 + offset + 3;
|
||||
|
@@ -26,6 +26,7 @@ namespace nall {
|
||||
public:
|
||||
inline operator bool() const { return valid; }
|
||||
inline const T& operator()() const { if(!valid) throw; return value; }
|
||||
inline optional<T>& operator=(const optional<T> &source) { valid = source.valid; value = source.value; return *this; }
|
||||
inline optional(bool valid, const T &value) : valid(valid), value(value) {}
|
||||
};
|
||||
|
||||
|
@@ -94,14 +94,15 @@ namespace nall {
|
||||
else resize(objectsize - count);
|
||||
}
|
||||
|
||||
inline T& operator[](unsigned index) {
|
||||
if(index >= objectsize) resize(index + 1);
|
||||
return pool[index];
|
||||
linear_vector() : pool(0), poolsize(0), objectsize(0) {
|
||||
}
|
||||
|
||||
inline const T& operator[](unsigned index) const {
|
||||
if(index >= objectsize) throw "vector[] out of bounds";
|
||||
return pool[index];
|
||||
linear_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
|
||||
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
|
||||
}
|
||||
|
||||
~linear_vector() {
|
||||
reset();
|
||||
}
|
||||
|
||||
//copy
|
||||
@@ -132,17 +133,22 @@ namespace nall {
|
||||
operator=(std::move(source));
|
||||
}
|
||||
|
||||
//construction
|
||||
linear_vector() : pool(0), poolsize(0), objectsize(0) {
|
||||
//index
|
||||
inline T& operator[](unsigned index) {
|
||||
if(index >= objectsize) resize(index + 1);
|
||||
return pool[index];
|
||||
}
|
||||
|
||||
linear_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
|
||||
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
|
||||
inline const T& operator[](unsigned index) const {
|
||||
if(index >= objectsize) throw "vector[] out of bounds";
|
||||
return pool[index];
|
||||
}
|
||||
|
||||
~linear_vector() {
|
||||
reset();
|
||||
}
|
||||
//iteration
|
||||
T* begin() { return &pool[0]; }
|
||||
T* end() { return &pool[objectsize]; }
|
||||
const T* begin() const { return &pool[0]; }
|
||||
const T* end() const { return &pool[objectsize]; }
|
||||
};
|
||||
|
||||
//pointer_vector
|
||||
@@ -222,15 +228,15 @@ namespace nall {
|
||||
else resize(objectsize - count);
|
||||
}
|
||||
|
||||
inline T& operator[](unsigned index) {
|
||||
if(index >= objectsize) resize(index + 1);
|
||||
if(!pool[index]) pool[index] = new T;
|
||||
return *pool[index];
|
||||
pointer_vector() : pool(0), poolsize(0), objectsize(0) {
|
||||
}
|
||||
|
||||
inline const T& operator[](unsigned index) const {
|
||||
if(index >= objectsize || !pool[index]) throw "vector[] out of bounds";
|
||||
return *pool[index];
|
||||
pointer_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
|
||||
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
|
||||
}
|
||||
|
||||
~pointer_vector() {
|
||||
reset();
|
||||
}
|
||||
|
||||
//copy
|
||||
@@ -261,17 +267,31 @@ namespace nall {
|
||||
operator=(std::move(source));
|
||||
}
|
||||
|
||||
//construction
|
||||
pointer_vector() : pool(0), poolsize(0), objectsize(0) {
|
||||
//index
|
||||
inline T& operator[](unsigned index) {
|
||||
if(index >= objectsize) resize(index + 1);
|
||||
if(!pool[index]) pool[index] = new T;
|
||||
return *pool[index];
|
||||
}
|
||||
|
||||
pointer_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
|
||||
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
|
||||
inline const T& operator[](unsigned index) const {
|
||||
if(index >= objectsize || !pool[index]) throw "vector[] out of bounds";
|
||||
return *pool[index];
|
||||
}
|
||||
|
||||
~pointer_vector() {
|
||||
reset();
|
||||
}
|
||||
//iteration
|
||||
struct iterator {
|
||||
bool operator!=(const iterator &source) const { return index != source.index; }
|
||||
T& operator*() { return vector.operator[](index); }
|
||||
iterator& operator++() { index++; return *this; }
|
||||
iterator(pointer_vector &vector, unsigned index) : vector(vector), index(index) {}
|
||||
private:
|
||||
pointer_vector &vector;
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(*this, 0); }
|
||||
iterator end() { return iterator(*this, objectsize); }
|
||||
};
|
||||
|
||||
template<typename T> struct has_size<linear_vector<T>> { enum { value = true }; };
|
||||
|
192
bsnes/nall/windows/detour.hpp
Executable file
192
bsnes/nall/windows/detour.hpp
Executable file
@@ -0,0 +1,192 @@
|
||||
#ifndef NALL_WINDOWS_DETOUR_HPP
|
||||
#define NALL_WINDOWS_DETOUR_HPP
|
||||
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
#define Copy 0
|
||||
#define RelNear 1
|
||||
|
||||
struct detour {
|
||||
static bool insert(const string &moduleName, const string &functionName, void *&source, void *target);
|
||||
static bool remove(const string &moduleName, const string &functionName, void *&source);
|
||||
|
||||
protected:
|
||||
static unsigned length(const uint8_t *function);
|
||||
static unsigned mirror(uint8_t *target, const uint8_t *source);
|
||||
|
||||
struct opcode {
|
||||
uint16_t prefix;
|
||||
unsigned length;
|
||||
unsigned mode;
|
||||
uint16_t modify;
|
||||
};
|
||||
static opcode opcodes[];
|
||||
};
|
||||
|
||||
//TODO:
|
||||
//* fs:, gs: should force another opcode copy
|
||||
//* conditional branches within +5-byte range should fail
|
||||
detour::opcode detour::opcodes[] = {
|
||||
{ 0x50, 1 }, //push eax
|
||||
{ 0x51, 1 }, //push ecx
|
||||
{ 0x52, 1 }, //push edx
|
||||
{ 0x53, 1 }, //push ebx
|
||||
{ 0x54, 1 }, //push esp
|
||||
{ 0x55, 1 }, //push ebp
|
||||
{ 0x56, 1 }, //push esi
|
||||
{ 0x57, 1 }, //push edi
|
||||
{ 0x58, 1 }, //pop eax
|
||||
{ 0x59, 1 }, //pop ecx
|
||||
{ 0x5a, 1 }, //pop edx
|
||||
{ 0x5b, 1 }, //pop ebx
|
||||
{ 0x5c, 1 }, //pop esp
|
||||
{ 0x5d, 1 }, //pop ebp
|
||||
{ 0x5e, 1 }, //pop esi
|
||||
{ 0x5f, 1 }, //pop edi
|
||||
{ 0x64, 1 }, //fs:
|
||||
{ 0x65, 1 }, //gs:
|
||||
{ 0x68, 5 }, //push dword
|
||||
{ 0x6a, 2 }, //push byte
|
||||
{ 0x74, 2, RelNear, 0x0f84 }, //je near -> je far
|
||||
{ 0x75, 2, RelNear, 0x0f85 }, //jne near -> jne far
|
||||
{ 0x89, 2 }, //mov reg,reg
|
||||
{ 0x8b, 2 }, //mov reg,reg
|
||||
{ 0x90, 1 }, //nop
|
||||
{ 0xa1, 5 }, //mov eax,[dword]
|
||||
{ 0xeb, 2, RelNear, 0xe9 }, //jmp near -> jmp far
|
||||
};
|
||||
|
||||
bool detour::insert(const string &moduleName, const string &functionName, void *&source, void *target) {
|
||||
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
|
||||
if(!module) return false;
|
||||
|
||||
uint8_t *sourceData = (uint8_t*)GetProcAddress(module, functionName);
|
||||
if(!sourceData) return false;
|
||||
|
||||
unsigned sourceLength = detour::length(sourceData);
|
||||
if(sourceLength < 5) {
|
||||
//unable to clone enough bytes to insert hook
|
||||
#if 1
|
||||
string output = { "detour::insert(", moduleName, "::", functionName, ") failed: " };
|
||||
for(unsigned n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " ");
|
||||
output.rtrim<1>(" ");
|
||||
MessageBoxA(0, output, "nall::detour", MB_OK);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *mirrorData = new uint8_t[512]();
|
||||
detour::mirror(mirrorData, sourceData);
|
||||
|
||||
DWORD privileges;
|
||||
VirtualProtect((void*)mirrorData, 512, PAGE_EXECUTE_READWRITE, &privileges);
|
||||
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
|
||||
uintmax_t address = (uintmax_t)target - ((uintmax_t)sourceData + 5);
|
||||
sourceData[0] = 0xe9; //jmp target
|
||||
sourceData[1] = address >> 0;
|
||||
sourceData[2] = address >> 8;
|
||||
sourceData[3] = address >> 16;
|
||||
sourceData[4] = address >> 24;
|
||||
VirtualProtect((void*)sourceData, 256, privileges, &privileges);
|
||||
|
||||
source = (void*)mirrorData;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool detour::remove(const string &moduleName, const string &functionName, void *&source) {
|
||||
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
|
||||
if(!module) return false;
|
||||
|
||||
uint8_t *sourceData = (uint8_t*)GetProcAddress(module, functionName);
|
||||
if(!sourceData) return false;
|
||||
|
||||
uint8_t *mirrorData = (uint8_t*)source;
|
||||
if(mirrorData == sourceData) return false; //hook was never installed
|
||||
|
||||
unsigned length = detour::length(256 + mirrorData);
|
||||
if(length < 5) return false;
|
||||
|
||||
DWORD privileges;
|
||||
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
|
||||
for(unsigned n = 0; n < length; n++) sourceData[n] = mirrorData[256 + n];
|
||||
VirtualProtect((void*)sourceData, 256, privileges, &privileges);
|
||||
|
||||
source = (void*)sourceData;
|
||||
delete[] mirrorData;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned detour::length(const uint8_t *function) {
|
||||
unsigned length = 0;
|
||||
while(length < 5) {
|
||||
detour::opcode *opcode = 0;
|
||||
foreach(op, detour::opcodes) {
|
||||
if(function[length] == op.prefix) {
|
||||
opcode = &op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(opcode == 0) break;
|
||||
length += opcode->length;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
unsigned detour::mirror(uint8_t *target, const uint8_t *source) {
|
||||
const uint8_t *entryPoint = source;
|
||||
for(unsigned n = 0; n < 256; n++) target[256 + n] = source[n];
|
||||
|
||||
unsigned size = detour::length(source);
|
||||
while(size) {
|
||||
detour::opcode *opcode = 0;
|
||||
foreach(op, detour::opcodes) {
|
||||
if(*source == op.prefix) {
|
||||
opcode = &op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(opcode->mode) {
|
||||
case Copy:
|
||||
for(unsigned n = 0; n < opcode->length; n++) *target++ = *source++;
|
||||
break;
|
||||
case RelNear: {
|
||||
source++;
|
||||
uintmax_t sourceAddress = (uintmax_t)source + 1 + (int8_t)*source;
|
||||
*target++ = opcode->modify;
|
||||
if(opcode->modify >> 8) *target++ = opcode->modify >> 8;
|
||||
uintmax_t targetAddress = (uintmax_t)target + 4;
|
||||
uintmax_t address = sourceAddress - targetAddress;
|
||||
*target++ = address >> 0;
|
||||
*target++ = address >> 8;
|
||||
*target++ = address >> 16;
|
||||
*target++ = address >> 24;
|
||||
source += 2;
|
||||
} break;
|
||||
}
|
||||
|
||||
size -= opcode->length;
|
||||
}
|
||||
|
||||
uintmax_t address = (entryPoint + detour::length(entryPoint)) - (target + 5);
|
||||
*target++ = 0xe9; //jmp entryPoint
|
||||
*target++ = address >> 0;
|
||||
*target++ = address >> 8;
|
||||
*target++ = address >> 16;
|
||||
*target++ = address >> 24;
|
||||
|
||||
return source - entryPoint;
|
||||
}
|
||||
|
||||
#undef Implied
|
||||
#undef RelNear
|
||||
|
||||
}
|
||||
|
||||
#endif
|
94
bsnes/nall/windows/launcher.hpp
Executable file
94
bsnes/nall/windows/launcher.hpp
Executable file
@@ -0,0 +1,94 @@
|
||||
#ifndef NALL_WINDOWS_LAUNCHER_HPP
|
||||
#define NALL_WINDOWS_LAUNCHER_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
//launch a new process and inject specified DLL into it
|
||||
|
||||
bool launch(const char *applicationName, const char *libraryName, uint32_t entryPoint) {
|
||||
//if a launcher does not send at least one message, a wait cursor will appear
|
||||
PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
|
||||
MSG msg;
|
||||
GetMessage(&msg, 0, 0, 0);
|
||||
|
||||
STARTUPINFOW si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
memset(&si, 0, sizeof(STARTUPINFOW));
|
||||
BOOL result = CreateProcessW(
|
||||
utf16_t(applicationName), GetCommandLineW(), NULL, NULL, TRUE,
|
||||
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, //do not break if application creates its own processes
|
||||
NULL, NULL, &si, &pi
|
||||
);
|
||||
if(result == false) return false;
|
||||
|
||||
uint8_t entryData[1024], entryHook[1024] = {
|
||||
0x68, 0x00, 0x00, 0x00, 0x00, //push libraryName
|
||||
0xb8, 0x00, 0x00, 0x00, 0x00, //mov eax,LoadLibraryW
|
||||
0xff, 0xd0, //call eax
|
||||
0xcd, 0x03, //int 3
|
||||
};
|
||||
|
||||
entryHook[1] = (uint8_t)((entryPoint + 14) >> 0);
|
||||
entryHook[2] = (uint8_t)((entryPoint + 14) >> 8);
|
||||
entryHook[3] = (uint8_t)((entryPoint + 14) >> 16);
|
||||
entryHook[4] = (uint8_t)((entryPoint + 14) >> 24);
|
||||
|
||||
uint32_t pLoadLibraryW = (uint32_t)GetProcAddress(GetModuleHandleW(L"kernel32"), "LoadLibraryW");
|
||||
entryHook[6] = pLoadLibraryW >> 0;
|
||||
entryHook[7] = pLoadLibraryW >> 8;
|
||||
entryHook[8] = pLoadLibraryW >> 16;
|
||||
entryHook[9] = pLoadLibraryW >> 24;
|
||||
|
||||
utf16_t buffer = utf16_t(libraryName);
|
||||
memcpy(entryHook + 14, buffer, 2 * wcslen(buffer) + 2);
|
||||
|
||||
while(true) {
|
||||
DEBUG_EVENT event;
|
||||
WaitForDebugEvent(&event, INFINITE);
|
||||
|
||||
if(event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break;
|
||||
|
||||
if(event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) {
|
||||
if(event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) {
|
||||
if(event.u.Exception.ExceptionRecord.ExceptionAddress == (void*)(entryPoint + 14 - 1)) {
|
||||
HANDLE hProcess = OpenProcess(0, FALSE, event.dwProcessId);
|
||||
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, event.dwThreadId);
|
||||
|
||||
CONTEXT context;
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
GetThreadContext(hThread, &context);
|
||||
|
||||
WriteProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryData, sizeof entryData, NULL);
|
||||
context.Eip = entryPoint;
|
||||
SetThreadContext(hThread, &context);
|
||||
|
||||
CloseHandle(hThread);
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
|
||||
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
|
||||
continue;
|
||||
}
|
||||
|
||||
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
|
||||
ReadProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryData, sizeof entryData, NULL);
|
||||
WriteProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryHook, sizeof entryHook, NULL);
|
||||
|
||||
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
|
||||
continue;
|
||||
}
|
||||
|
||||
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
124
bsnes/nall/zip.hpp
Executable file
124
bsnes/nall/zip.hpp
Executable file
@@ -0,0 +1,124 @@
|
||||
#ifndef NALL_UNZIP_HPP
|
||||
#define NALL_UNZIP_HPP
|
||||
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/inflate.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct zip {
|
||||
struct File {
|
||||
string name;
|
||||
const uint8_t *data;
|
||||
unsigned size;
|
||||
unsigned csize;
|
||||
unsigned cmode; //0 = uncompressed, 8 = deflate
|
||||
unsigned crc32;
|
||||
};
|
||||
|
||||
inline bool open(const string &filename) {
|
||||
close();
|
||||
if(fm.open(filename, filemap::mode::read) == false) return false;
|
||||
if(open(fm.data(), fm.size()) == false) {
|
||||
fm.close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool open(const uint8_t *data, unsigned size) {
|
||||
if(size < 22) return false;
|
||||
|
||||
filedata = data;
|
||||
filesize = size;
|
||||
|
||||
file.reset();
|
||||
|
||||
const uint8_t *footer = data + size - 22;
|
||||
const uint8_t *directory = data + read(footer + 16, 4);
|
||||
|
||||
while(true) {
|
||||
unsigned signature = read(directory + 0, 4);
|
||||
if(signature != 0x02014b50) break;
|
||||
|
||||
File file;
|
||||
file.cmode = read(directory + 10, 2);
|
||||
file.crc32 = read(directory + 16, 4);
|
||||
file.csize = read(directory + 20, 4);
|
||||
file.size = read(directory + 24, 4);
|
||||
|
||||
unsigned namelength = read(directory + 28, 2);
|
||||
unsigned extralength = read(directory + 30, 2);
|
||||
unsigned commentlength = read(directory + 32, 2);
|
||||
|
||||
char *filename = new char[namelength + 1];
|
||||
memcpy(filename, directory + 46, namelength);
|
||||
filename[namelength] = 0;
|
||||
file.name = filename;
|
||||
delete[] filename;
|
||||
|
||||
unsigned offset = read(directory + 42, 4);
|
||||
unsigned offsetNL = read(data + offset + 26, 2);
|
||||
unsigned offsetEL = read(data + offset + 28, 2);
|
||||
file.data = data + offset + 30 + offsetNL + offsetEL;
|
||||
|
||||
directory += 46 + namelength + extralength + commentlength;
|
||||
|
||||
this->file.append(file);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool extract(File &file, uint8_t *&data, unsigned &size) {
|
||||
data = 0, size = 0;
|
||||
|
||||
if(file.cmode == 0) {
|
||||
size = file.size;
|
||||
data = new uint8_t[size];
|
||||
memcpy(data, file.data, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(file.cmode == 8) {
|
||||
size = file.size;
|
||||
data = new uint8_t[size];
|
||||
if(inflate(data, size, file.data, file.csize) == false) {
|
||||
delete[] data;
|
||||
size = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void close() {
|
||||
if(fm.open()) fm.close();
|
||||
}
|
||||
|
||||
~zip() {
|
||||
close();
|
||||
}
|
||||
|
||||
protected:
|
||||
filemap fm;
|
||||
const uint8_t *filedata;
|
||||
unsigned filesize;
|
||||
|
||||
unsigned read(const uint8_t *data, unsigned size) {
|
||||
unsigned result = 0, shift = 0;
|
||||
while(size--) { result |= *data++ << shift; shift += 8; }
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
linear_vector<File> file;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
193
bsnes/phoenix/core/core.cpp
Executable file
193
bsnes/phoenix/core/core.cpp
Executable file
@@ -0,0 +1,193 @@
|
||||
#include "state.hpp"
|
||||
#include "layout/fixed-layout.cpp"
|
||||
#include "layout/horizontal-layout.cpp"
|
||||
#include "layout/vertical-layout.cpp"
|
||||
|
||||
#if defined(PHOENIX_WINDOWS)
|
||||
#include "../windows/windows.cpp"
|
||||
#elif defined(PHOENIX_QT)
|
||||
#include "../qt/qt.cpp"
|
||||
#elif defined(PHOENIX_GTK)
|
||||
#include "../gtk/gtk.cpp"
|
||||
#elif defined(PHOENIX_REFERENCE)
|
||||
#include "../reference/reference.cpp"
|
||||
#endif
|
||||
|
||||
Object::Object() { OS::initialize(); }
|
||||
|
||||
Geometry OS::availableGeometry() { return pOS::availableGeometry(); }
|
||||
Geometry OS::desktopGeometry() { return pOS::desktopGeometry(); }
|
||||
string OS::fileLoad_(Window &parent, const string &path, const lstring &filter_) { auto filter = filter_; if(filter.size() == 0) filter.append("All files (*)"); return pOS::fileLoad(parent, path, filter); }
|
||||
string OS::fileSave_(Window &parent, const string &path, const lstring &filter_) { auto filter = filter_; if(filter.size() == 0) filter.append("All files (*)"); return pOS::fileSave(parent, path, filter); }
|
||||
string OS::folderSelect(Window &parent, const string &path) { return pOS::folderSelect(parent, path); }
|
||||
void OS::main() { return pOS::main(); }
|
||||
bool OS::pendingEvents() { return pOS::pendingEvents(); }
|
||||
void OS::processEvents() { return pOS::processEvents(); }
|
||||
void OS::quit() { return pOS::quit(); }
|
||||
void OS::initialize() { static bool initialized = false; if(initialized == false) { initialized = true; return pOS::initialize(); } }
|
||||
|
||||
Geometry Font::geometry(const string &text) { return p.geometry(text); }
|
||||
void Font::setBold(bool bold) { state.bold = bold; return p.setBold(bold); }
|
||||
void Font::setFamily(const string &family) { state.family = family; return p.setFamily(family); }
|
||||
void Font::setItalic(bool italic) { state.italic = italic; return p.setItalic(italic); }
|
||||
void Font::setSize(unsigned size) { state.size = size; return p.setSize(size); }
|
||||
void Font::setUnderline(bool underline) { state.underline = underline; return p.setUnderline(underline); }
|
||||
Font::Font() : state(*new State), p(*new pFont(*this)) { p.constructor(); }
|
||||
|
||||
void Timer::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); }
|
||||
void Timer::setInterval(unsigned milliseconds) { state.milliseconds = milliseconds; return p.setInterval(milliseconds); }
|
||||
Timer::Timer() : state(*new State), p(*new pTimer(*this)) { p.constructor(); }
|
||||
|
||||
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::information(parent, text, buttons); }
|
||||
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::question(parent, text, buttons); }
|
||||
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::warning(parent, text, buttons); }
|
||||
MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::critical(parent, text, buttons); }
|
||||
|
||||
Window Window::None;
|
||||
void Window::append(Layout &layout) { state.layout.append(layout); return p.append(layout); }
|
||||
void Window::append(Menu &menu) { state.menu.append(menu); ((Action&)menu).state.parent = this; return p.append(menu); }
|
||||
void Window::append(Widget &widget) { state.widget.append(widget); return p.append(widget); }
|
||||
Color Window::backgroundColor() { return p.backgroundColor(); }
|
||||
Geometry Window::frameGeometry() { Geometry geometry = p.geometry(), margin = p.frameMargin(); return { geometry.x - margin.x, geometry.y - margin.y, geometry.width + margin.width, geometry.height + margin.height }; }
|
||||
Geometry Window::frameMargin() { return p.frameMargin(); }
|
||||
bool Window::focused() { return p.focused(); }
|
||||
Geometry Window::geometry() { return p.geometry(); }
|
||||
void Window::setBackgroundColor(const Color &color) { state.backgroundColorOverride = true; state.backgroundColor = color; return p.setBackgroundColor(color); }
|
||||
void Window::setFrameGeometry(const Geometry &geometry) { Geometry margin = p.frameMargin(); return setGeometry({ geometry.x + margin.x, geometry.y + margin.y, geometry.width - margin.width, geometry.height - margin.height }); }
|
||||
void Window::setFocused() { return p.setFocused(); }
|
||||
void Window::setFullScreen(bool fullScreen) { state.fullScreen = fullScreen; return p.setFullScreen(fullScreen); }
|
||||
void Window::setGeometry(const Geometry &geometry) { state.geometry = geometry; return p.setGeometry(geometry); }
|
||||
void Window::setMenuFont(Font &font) { state.menuFont = &font; return p.setMenuFont(font); }
|
||||
void Window::setMenuVisible(bool visible) { state.menuVisible = visible; return p.setMenuVisible(visible); }
|
||||
void Window::setResizable(bool resizable) { state.resizable = resizable; return p.setResizable(resizable); }
|
||||
void Window::setStatusFont(Font &font) { state.statusFont = &font; return p.setStatusFont(font); }
|
||||
void Window::setStatusText(const string &text) { state.statusText = text; return p.setStatusText(text); }
|
||||
void Window::setStatusVisible(bool visible) { state.statusVisible = visible; return p.setStatusVisible(visible); }
|
||||
void Window::setTitle(const string &text) { state.title = text; return p.setTitle(text); }
|
||||
void Window::setVisible(bool visible) { state.visible = visible; return p.setVisible(visible); }
|
||||
void Window::setWidgetFont(Font &font) { state.widgetFont = &font; return p.setWidgetFont(font); }
|
||||
Window::Window() : state(*new State), p(*new pWindow(*this)) { p.constructor(); }
|
||||
|
||||
void Action::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); }
|
||||
void Action::setVisible(bool visible) { state.visible = visible; return p.setVisible(visible); }
|
||||
Action::Action(pAction &p) : state(*new State), p(p) { p.constructor(); }
|
||||
|
||||
void Menu::append(Action &action) { state.action.append(action); return p.append(action); }
|
||||
void Menu::setText(const string &text) { state.text = text; return p.setText(text); }
|
||||
Menu::Menu() : state(*new State), base_from_member<pMenu&>(*new pMenu(*this)), Action(base_from_member<pMenu&>::value), p(base_from_member<pMenu&>::value) { p.constructor(); }
|
||||
|
||||
Separator::Separator() : base_from_member<pSeparator&>(*new pSeparator(*this)), Action(base_from_member<pSeparator&>::value), p(base_from_member<pSeparator&>::value) { p.constructor(); }
|
||||
|
||||
void Item::setText(const string &text) { state.text = text; return p.setText(text); }
|
||||
Item::Item() : state(*new State), base_from_member<pItem&>(*new pItem(*this)), Action(base_from_member<pItem&>::value), p(base_from_member<pItem&>::value) { p.constructor(); }
|
||||
|
||||
bool CheckItem::checked() { return p.checked(); }
|
||||
void CheckItem::setChecked(bool checked) { state.checked = checked; return p.setChecked(checked); }
|
||||
void CheckItem::setText(const string &text) { state.text = text; return p.setText(text); }
|
||||
CheckItem::CheckItem() : state(*new State), base_from_member<pCheckItem&>(*new pCheckItem(*this)), Action(base_from_member<pCheckItem&>::value), p(base_from_member<pCheckItem&>::value) { p.constructor(); }
|
||||
|
||||
void RadioItem::group(const reference_array<RadioItem&> &list) { foreach(item, list) item.p.setGroup(item.state.group = list); if(list.size()) list[0].setChecked(); }
|
||||
bool RadioItem::checked() { return p.checked(); }
|
||||
void RadioItem::setChecked() { foreach(item, state.group) item.state.checked = false; state.checked = true; return p.setChecked(); }
|
||||
void RadioItem::setText(const string &text) { state.text = text; return p.setText(text); }
|
||||
RadioItem::RadioItem() : state(*new State), base_from_member<pRadioItem&>(*new pRadioItem(*this)), Action(base_from_member<pRadioItem&>::value), p(base_from_member<pRadioItem&>::value) { p.constructor(); }
|
||||
|
||||
bool Widget::enabled() { return state.enabled; }
|
||||
Font& Widget::font() { return p.font(); }
|
||||
Geometry Widget::geometry() { return state.geometry; }
|
||||
Geometry Widget::minimumGeometry() { return p.minimumGeometry(); }
|
||||
void Widget::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); }
|
||||
void Widget::setFocused() { return p.setFocused(); }
|
||||
void Widget::setFont(Font &font) { state.font = &font; return p.setFont(font); }
|
||||
void Widget::setGeometry(const Geometry &geometry) { state.geometry = geometry; return p.setGeometry(geometry); }
|
||||
void Widget::setVisible(bool visible) { state.visible = visible; return p.setVisible(visible); }
|
||||
bool Widget::visible() { return state.visible; }
|
||||
Widget::Widget() : state(*new State), p(*new pWidget(*this)) { state.abstract = true; p.constructor(); }
|
||||
Widget::Widget(pWidget &p) : state(*new State), p(p) { p.constructor(); }
|
||||
|
||||
void Button::setText(const string &text) { state.text = text; return p.setText(text); }
|
||||
Button::Button() : state(*new State), base_from_member<pButton&>(*new pButton(*this)), Widget(base_from_member<pButton&>::value), p(base_from_member<pButton&>::value) { p.constructor(); }
|
||||
|
||||
uint32_t* Canvas::buffer() { return p.buffer(); }
|
||||
void Canvas::update() { return p.update(); }
|
||||
Canvas::Canvas() : base_from_member<pCanvas&>(*new pCanvas(*this)), Widget(base_from_member<pCanvas&>::value), p(base_from_member<pCanvas&>::value) { p.constructor(); }
|
||||
|
||||
bool CheckBox::checked() { return p.checked(); }
|
||||
void CheckBox::setChecked(bool checked) { state.checked = checked; return p.setChecked(checked); }
|
||||
void CheckBox::setText(const string &text) { state.text = text; return p.setText(text); }
|
||||
CheckBox::CheckBox() : state(*new State), base_from_member<pCheckBox&>(*new pCheckBox(*this)), Widget(base_from_member<pCheckBox&>::value), p(base_from_member<pCheckBox&>::value) { p.constructor(); }
|
||||
|
||||
void ComboBox::append(const string &text) { state.text.append(text); return p.append(text); }
|
||||
void ComboBox::reset() { state.selection = 0; state.text.reset(); return p.reset(); }
|
||||
unsigned ComboBox::selection() { return p.selection(); }
|
||||
void ComboBox::setSelection(unsigned row) { state.selection = row; return p.setSelection(row); }
|
||||
ComboBox::ComboBox() : state(*new State), base_from_member<pComboBox&>(*new pComboBox(*this)), Widget(base_from_member<pComboBox&>::value), p(base_from_member<pComboBox&>::value) { p.constructor(); }
|
||||
|
||||
void HexEdit::setColumns(unsigned columns) { state.columns = columns; return p.setColumns(columns); }
|
||||
void HexEdit::setLength(unsigned length) { state.length = length; return p.setLength(length); }
|
||||
void HexEdit::setOffset(unsigned offset) { state.offset = offset; return p.setOffset(offset); }
|
||||
void HexEdit::setRows(unsigned rows) { state.rows = rows; return p.setRows(rows); }
|
||||
void HexEdit::update() { return p.update(); }
|
||||
HexEdit::HexEdit() : state(*new State), base_from_member<pHexEdit&>(*new pHexEdit(*this)), Widget(base_from_member<pHexEdit&>::value), p(base_from_member<pHexEdit&>::value) { p.constructor(); }
|
||||
|
||||
unsigned HorizontalScrollBar::position() { return p.position(); }
|
||||
void HorizontalScrollBar::setLength(unsigned length) { state.length = length; return p.setLength(length); }
|
||||
void HorizontalScrollBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
|
||||
HorizontalScrollBar::HorizontalScrollBar() : state(*new State), base_from_member<pHorizontalScrollBar&>(*new pHorizontalScrollBar(*this)), Widget(base_from_member<pHorizontalScrollBar&>::value), p(base_from_member<pHorizontalScrollBar&>::value) { p.constructor(); }
|
||||
|
||||
unsigned HorizontalSlider::position() { return p.position(); }
|
||||
void HorizontalSlider::setLength(unsigned length) { state.length = length; return p.setLength(length); }
|
||||
void HorizontalSlider::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
|
||||
HorizontalSlider::HorizontalSlider() : state(*new State), base_from_member<pHorizontalSlider&>(*new pHorizontalSlider(*this)), Widget(base_from_member<pHorizontalSlider&>::value), p(base_from_member<pHorizontalSlider&>::value) { p.constructor(); }
|
||||
|
||||
void Label::setText(const string &text) { state.text = text; return p.setText(text); }
|
||||
Label::Label() : state(*new State), base_from_member<pLabel&>(*new pLabel(*this)), Widget(base_from_member<pLabel&>::value), p(base_from_member<pLabel&>::value) { p.constructor(); }
|
||||
|
||||
void LineEdit::setEditable(bool editable) { state.editable = editable; return p.setEditable(editable); }
|
||||
void LineEdit::setText(const string &text) { state.text = text; return p.setText(text); }
|
||||
string LineEdit::text() { return p.text(); }
|
||||
LineEdit::LineEdit() : state(*new State), base_from_member<pLineEdit&>(*new pLineEdit(*this)), Widget(base_from_member<pLineEdit&>::value), p(base_from_member<pLineEdit&>::value) { p.constructor(); }
|
||||
|
||||
void ListView::append_(const lstring &text) { state.checked.append(false); state.text.append(text); return p.append(text); }
|
||||
void ListView::autoSizeColumns() { return p.autoSizeColumns(); }
|
||||
bool ListView::checked(unsigned row) { return p.checked(row); }
|
||||
void ListView::modify_(unsigned row, const lstring &text) { state.text[row] = text; return p.modify(row, text); }
|
||||
void ListView::reset() { state.checked.reset(); state.text.reset(); return p.reset(); }
|
||||
bool ListView::selected() { return p.selected(); }
|
||||
unsigned ListView::selection() { return p.selection(); }
|
||||
void ListView::setCheckable(bool checkable) { state.checkable = checkable; return p.setCheckable(checkable); }
|
||||
void ListView::setChecked(unsigned row, bool checked) { state.checked[row] = checked; return p.setChecked(row, checked); }
|
||||
void ListView::setHeaderText_(const lstring &text) { state.headerText = text; return p.setHeaderText(text); }
|
||||
void ListView::setHeaderVisible(bool visible) { state.headerVisible = visible; return p.setHeaderVisible(visible); }
|
||||
void ListView::setSelected(bool selected) { state.selected = selected; return p.setSelected(selected); }
|
||||
void ListView::setSelection(unsigned row) { state.selected = true; state.selection = row; return p.setSelection(row); }
|
||||
ListView::ListView() : state(*new State), base_from_member<pListView&>(*new pListView(*this)), Widget(base_from_member<pListView&>::value), p(base_from_member<pListView&>::value) { p.constructor(); }
|
||||
|
||||
void ProgressBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
|
||||
ProgressBar::ProgressBar() : state(*new State), base_from_member<pProgressBar&>(*new pProgressBar(*this)), Widget(base_from_member<pProgressBar&>::value), p(base_from_member<pProgressBar&>::value) { p.constructor(); }
|
||||
|
||||
void RadioBox::group(const reference_array<RadioBox&> &list) { foreach(item, list) item.p.setGroup(item.state.group = list); if(list.size()) list[0].setChecked(); }
|
||||
bool RadioBox::checked() { return p.checked(); }
|
||||
void RadioBox::setChecked() { foreach(item, state.group) item.state.checked = false; state.checked = true; return p.setChecked(); }
|
||||
void RadioBox::setText(const string &text) { state.text = text; return p.setText(text); }
|
||||
RadioBox::RadioBox() : state(*new State), base_from_member<pRadioBox&>(*new pRadioBox(*this)), Widget(base_from_member<pRadioBox&>::value), p(base_from_member<pRadioBox&>::value) { p.constructor(); }
|
||||
|
||||
void TextEdit::setCursorPosition(unsigned position) { state.cursorPosition = position; return p.setCursorPosition(position); }
|
||||
void TextEdit::setEditable(bool editable) { state.editable = editable; return p.setEditable(editable); }
|
||||
void TextEdit::setText(const string &text) { state.text = text; return p.setText(text); }
|
||||
void TextEdit::setWordWrap(bool wordWrap) { state.wordWrap = wordWrap; return p.setWordWrap(wordWrap); }
|
||||
string TextEdit::text() { return p.text(); }
|
||||
TextEdit::TextEdit() : state(*new State), base_from_member<pTextEdit&>(*new pTextEdit(*this)), Widget(base_from_member<pTextEdit&>::value), p(base_from_member<pTextEdit&>::value) { p.constructor(); }
|
||||
|
||||
unsigned VerticalScrollBar::position() { return p.position(); }
|
||||
void VerticalScrollBar::setLength(unsigned length) { state.length = length; return p.setLength(length); }
|
||||
void VerticalScrollBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
|
||||
VerticalScrollBar::VerticalScrollBar() : state(*new State), base_from_member<pVerticalScrollBar&>(*new pVerticalScrollBar(*this)), Widget(base_from_member<pVerticalScrollBar&>::value), p(base_from_member<pVerticalScrollBar&>::value) { p.constructor(); }
|
||||
|
||||
unsigned VerticalSlider::position() { return p.position(); }
|
||||
void VerticalSlider::setLength(unsigned length) { state.length = length; return p.setLength(length); }
|
||||
void VerticalSlider::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
|
||||
VerticalSlider::VerticalSlider() : state(*new State), base_from_member<pVerticalSlider&>(*new pVerticalSlider(*this)), Widget(base_from_member<pVerticalSlider&>::value), p(base_from_member<pVerticalSlider&>::value) { p.constructor(); }
|
||||
|
||||
uintptr_t Viewport::handle() { return p.handle(); }
|
||||
Viewport::Viewport() : base_from_member<pViewport&>(*new pViewport(*this)), Widget(base_from_member<pViewport&>::value), p(base_from_member<pViewport&>::value) { p.constructor(); }
|
467
bsnes/phoenix/core/core.hpp
Executable file
467
bsnes/phoenix/core/core.hpp
Executable file
@@ -0,0 +1,467 @@
|
||||
struct Font;
|
||||
struct Window;
|
||||
struct Menu;
|
||||
struct Layout;
|
||||
struct Widget;
|
||||
|
||||
struct pOS;
|
||||
struct pFont;
|
||||
struct pTimer;
|
||||
struct pWindow;
|
||||
struct pAction;
|
||||
struct pMenu;
|
||||
struct pSeparator;
|
||||
struct pItem;
|
||||
struct pCheckItem;
|
||||
struct pRadioItem;
|
||||
struct pLayout;
|
||||
struct pWidget;
|
||||
struct pButton;
|
||||
struct pCanvas;
|
||||
struct pCheckBox;
|
||||
struct pComboBox;
|
||||
struct pHexEdit;
|
||||
struct pHorizontalScrollBar;
|
||||
struct pHorizontalSlider;
|
||||
struct pLabel;
|
||||
struct pLineEdit;
|
||||
struct pListView;
|
||||
struct pProgressBar;
|
||||
struct pRadioBox;
|
||||
struct pTextEdit;
|
||||
struct pVerticalScrollBar;
|
||||
struct pVerticalSlider;
|
||||
struct pViewport;
|
||||
|
||||
enum : unsigned {
|
||||
MaximumSize = ~0u,
|
||||
MinimumSize = 0u,
|
||||
};
|
||||
|
||||
struct Geometry {
|
||||
signed x, y;
|
||||
unsigned width, height;
|
||||
inline Geometry() : x(0), y(0), width(0), height(0) {}
|
||||
inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
|
||||
};
|
||||
|
||||
struct Color {
|
||||
uint8_t red, green, blue, alpha;
|
||||
inline Color() : red(0), green(0), blue(0), alpha(255) {}
|
||||
inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {}
|
||||
};
|
||||
|
||||
struct Object {
|
||||
Object();
|
||||
Object& operator=(const Object&) = delete;
|
||||
Object(const Object&) = delete;
|
||||
virtual void unused() {} //allows dynamic_cast<> on Object
|
||||
};
|
||||
|
||||
struct OS : Object {
|
||||
static Geometry availableGeometry();
|
||||
static Geometry desktopGeometry();
|
||||
template<typename... Args> static nall::string fileLoad(Window &parent, const nall::string &path, const Args&... args) { return fileLoad_(parent, path, { args... }); }
|
||||
template<typename... Args> static nall::string fileSave(Window &parent, const nall::string &path, const Args&... args) { return fileSave_(parent, path, { args... }); }
|
||||
static nall::string folderSelect(Window &parent, const nall::string &path);
|
||||
static void main();
|
||||
static bool pendingEvents();
|
||||
static void processEvents();
|
||||
static void quit();
|
||||
|
||||
OS();
|
||||
static void initialize();
|
||||
|
||||
private:
|
||||
static nall::string fileLoad_(Window &parent, const nall::string &path, const nall::lstring& filter);
|
||||
static nall::string fileSave_(Window &parent, const nall::string &path, const nall::lstring& filter);
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
Geometry geometry(const nall::string &text);
|
||||
void setBold(bool bold = true);
|
||||
void setFamily(const nall::string &family);
|
||||
void setItalic(bool italic = true);
|
||||
void setSize(unsigned size);
|
||||
void setUnderline(bool underline = true);
|
||||
|
||||
Font();
|
||||
struct State;
|
||||
State &state;
|
||||
pFont &p;
|
||||
};
|
||||
|
||||
struct Timer : Object {
|
||||
nall::function<void ()> onTimeout;
|
||||
|
||||
void setEnabled(bool enabled = true);
|
||||
void setInterval(unsigned milliseconds);
|
||||
|
||||
Timer();
|
||||
struct State;
|
||||
State &state;
|
||||
pTimer &p;
|
||||
};
|
||||
|
||||
struct MessageWindow : Object {
|
||||
enum class Buttons : unsigned {
|
||||
Ok,
|
||||
OkCancel,
|
||||
YesNo,
|
||||
};
|
||||
|
||||
enum class Response : unsigned {
|
||||
Ok,
|
||||
Cancel,
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
|
||||
static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
};
|
||||
|
||||
struct Window : Object {
|
||||
static Window None;
|
||||
nall::function<void ()> onClose;
|
||||
nall::function<void ()> onMove;
|
||||
nall::function<void ()> onSize;
|
||||
|
||||
void append(Layout &layout);
|
||||
void append(Menu &menu);
|
||||
void append(Widget &widget);
|
||||
Color backgroundColor();
|
||||
Geometry frameGeometry();
|
||||
Geometry frameMargin();
|
||||
bool focused();
|
||||
Geometry geometry();
|
||||
void setBackgroundColor(const Color &color);
|
||||
void setFrameGeometry(const Geometry &geometry);
|
||||
void setFocused();
|
||||
void setFullScreen(bool fullScreen = true);
|
||||
void setGeometry(const Geometry &geometry);
|
||||
void setMenuFont(Font &font);
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setResizable(bool resizable = true);
|
||||
void setStatusFont(Font &font);
|
||||
void setStatusText(const nall::string &text);
|
||||
void setStatusVisible(bool visible = true);
|
||||
void setTitle(const nall::string &text);
|
||||
void setVisible(bool visible = true);
|
||||
void setWidgetFont(Font &font);
|
||||
|
||||
Window();
|
||||
struct State;
|
||||
State &state;
|
||||
pWindow &p;
|
||||
};
|
||||
|
||||
struct Action : Object {
|
||||
void setEnabled(bool enabled = true);
|
||||
void setVisible(bool visible = true);
|
||||
|
||||
Action(pAction &p);
|
||||
struct State;
|
||||
State &state;
|
||||
pAction &p;
|
||||
};
|
||||
|
||||
struct Menu : private nall::base_from_member<pMenu&>, Action {
|
||||
void append(Action &action);
|
||||
void setText(const nall::string &text);
|
||||
|
||||
Menu();
|
||||
struct State;
|
||||
State &state;
|
||||
pMenu &p;
|
||||
};
|
||||
|
||||
struct Separator : private nall::base_from_member<pSeparator&>, Action {
|
||||
Separator();
|
||||
pSeparator &p;
|
||||
};
|
||||
|
||||
struct Item : private nall::base_from_member<pItem&>, Action {
|
||||
nall::function<void ()> onTick;
|
||||
|
||||
void setText(const nall::string &text);
|
||||
|
||||
Item();
|
||||
struct State;
|
||||
State &state;
|
||||
pItem &p;
|
||||
};
|
||||
|
||||
struct CheckItem : private nall::base_from_member<pCheckItem&>, Action {
|
||||
nall::function<void ()> onTick;
|
||||
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
void setText(const nall::string &text);
|
||||
|
||||
CheckItem();
|
||||
struct State;
|
||||
State &state;
|
||||
pCheckItem &p;
|
||||
};
|
||||
|
||||
struct RadioItem : private nall::base_from_member<pRadioItem&>, Action {
|
||||
template<typename... Args> static void group(Args&... args) { group({ args... }); }
|
||||
static void group(const nall::reference_array<RadioItem&> &list);
|
||||
|
||||
nall::function<void ()> onTick;
|
||||
|
||||
bool checked();
|
||||
void setChecked();
|
||||
void setText(const nall::string &text);
|
||||
|
||||
RadioItem();
|
||||
struct State;
|
||||
State &state;
|
||||
pRadioItem &p;
|
||||
};
|
||||
|
||||
struct Layout : Object {
|
||||
virtual void setGeometry(const Geometry &geometry) = 0;
|
||||
virtual void setParent(Window &parent) = 0;
|
||||
virtual void setVisible(bool visible = true) = 0;
|
||||
};
|
||||
|
||||
struct Widget : Object {
|
||||
bool enabled();
|
||||
Font& font();
|
||||
Geometry geometry();
|
||||
Geometry minimumGeometry();
|
||||
void setEnabled(bool enabled = true);
|
||||
void setFocused();
|
||||
void setFont(Font &font);
|
||||
void setGeometry(const Geometry &geometry);
|
||||
void setVisible(bool visible = true);
|
||||
bool visible();
|
||||
|
||||
Widget();
|
||||
Widget(pWidget &p);
|
||||
struct State;
|
||||
State &state;
|
||||
pWidget &p;
|
||||
};
|
||||
|
||||
struct Button : private nall::base_from_member<pButton&>, Widget {
|
||||
nall::function<void ()> onTick;
|
||||
|
||||
void setText(const nall::string &text);
|
||||
|
||||
Button();
|
||||
struct State;
|
||||
State &state;
|
||||
pButton &p;
|
||||
};
|
||||
|
||||
struct Canvas : private nall::base_from_member<pCanvas&>, Widget {
|
||||
uint32_t* buffer();
|
||||
void update();
|
||||
|
||||
Canvas();
|
||||
pCanvas &p;
|
||||
};
|
||||
|
||||
struct CheckBox : private nall::base_from_member<pCheckBox&>, Widget {
|
||||
nall::function<void ()> onTick;
|
||||
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
void setText(const nall::string &text);
|
||||
|
||||
CheckBox();
|
||||
struct State;
|
||||
State &state;
|
||||
pCheckBox &p;
|
||||
};
|
||||
|
||||
struct ComboBox : private nall::base_from_member<pComboBox&>, Widget {
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
void append(const nall::string &text);
|
||||
void reset();
|
||||
unsigned selection();
|
||||
void setSelection(unsigned row);
|
||||
|
||||
ComboBox();
|
||||
struct State;
|
||||
State &state;
|
||||
pComboBox &p;
|
||||
};
|
||||
|
||||
struct HexEdit : private nall::base_from_member<pHexEdit&>, Widget {
|
||||
nall::function<uint8_t (unsigned)> onRead;
|
||||
nall::function<void (unsigned, uint8_t)> onWrite;
|
||||
|
||||
void setColumns(unsigned columns);
|
||||
void setLength(unsigned length);
|
||||
void setOffset(unsigned offset);
|
||||
void setRows(unsigned rows);
|
||||
void update();
|
||||
|
||||
HexEdit();
|
||||
struct State;
|
||||
State &state;
|
||||
pHexEdit &p;
|
||||
};
|
||||
|
||||
struct HorizontalScrollBar : private nall::base_from_member<pHorizontalScrollBar&>, Widget {
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
HorizontalScrollBar();
|
||||
struct State;
|
||||
State &state;
|
||||
pHorizontalScrollBar &p;
|
||||
};
|
||||
|
||||
struct HorizontalSlider : private nall::base_from_member<pHorizontalSlider&>, Widget {
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
HorizontalSlider();
|
||||
struct State;
|
||||
State &state;
|
||||
pHorizontalSlider &p;
|
||||
};
|
||||
|
||||
struct Label : private nall::base_from_member<pLabel&>, Widget {
|
||||
void setText(const nall::string &text);
|
||||
|
||||
Label();
|
||||
struct State;
|
||||
State &state;
|
||||
pLabel &p;
|
||||
};
|
||||
|
||||
struct LineEdit : private nall::base_from_member<pLineEdit&>, Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
void setEditable(bool editable = true);
|
||||
void setText(const nall::string &text);
|
||||
nall::string text();
|
||||
|
||||
LineEdit();
|
||||
struct State;
|
||||
State &state;
|
||||
pLineEdit &p;
|
||||
};
|
||||
|
||||
struct ListView : private nall::base_from_member<pListView&>, Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
nall::function<void (unsigned)> onTick;
|
||||
|
||||
template<typename... Args> void append(const Args&... args) { append_({ args... }); }
|
||||
void autoSizeColumns();
|
||||
bool checked(unsigned row);
|
||||
template<typename... Args> void modify(unsigned row, const Args&... args) { modify_(row, { args... }); }
|
||||
void reset();
|
||||
bool selected();
|
||||
unsigned selection();
|
||||
void setCheckable(bool checkable = true);
|
||||
void setChecked(unsigned row, bool checked = true);
|
||||
template<typename... Args> void setHeaderText(const Args&... args) { setHeaderText_({ args... }); }
|
||||
void setHeaderVisible(bool visible = true);
|
||||
void setSelected(bool selected = true);
|
||||
void setSelection(unsigned row);
|
||||
|
||||
ListView();
|
||||
struct State;
|
||||
State &state;
|
||||
pListView &p;
|
||||
|
||||
private:
|
||||
void append_(const nall::lstring &list);
|
||||
void modify_(unsigned row, const nall::lstring &list);
|
||||
void setHeaderText_(const nall::lstring &list);
|
||||
};
|
||||
|
||||
struct ProgressBar : private nall::base_from_member<pProgressBar&>, Widget {
|
||||
void setPosition(unsigned position);
|
||||
|
||||
ProgressBar();
|
||||
struct State;
|
||||
State &state;
|
||||
pProgressBar &p;
|
||||
};
|
||||
|
||||
struct RadioBox : private nall::base_from_member<pRadioBox&>, Widget {
|
||||
template<typename... Args> static void group(Args&... args) { group({ args... }); }
|
||||
static void group(const nall::reference_array<RadioBox&> &list);
|
||||
|
||||
nall::function<void ()> onTick;
|
||||
|
||||
bool checked();
|
||||
void setChecked();
|
||||
void setText(const nall::string &text);
|
||||
|
||||
RadioBox();
|
||||
struct State;
|
||||
State &state;
|
||||
pRadioBox &p;
|
||||
};
|
||||
|
||||
struct TextEdit : private nall::base_from_member<pTextEdit&>, Widget {
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
void setCursorPosition(unsigned position);
|
||||
void setEditable(bool editable = true);
|
||||
void setText(const nall::string &text);
|
||||
void setWordWrap(bool wordWrap = true);
|
||||
nall::string text();
|
||||
|
||||
TextEdit();
|
||||
struct State;
|
||||
State &state;
|
||||
pTextEdit &p;
|
||||
};
|
||||
|
||||
struct VerticalScrollBar : private nall::base_from_member<pVerticalScrollBar&>, Widget {
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
VerticalScrollBar();
|
||||
struct State;
|
||||
State &state;
|
||||
pVerticalScrollBar &p;
|
||||
};
|
||||
|
||||
struct VerticalSlider : private nall::base_from_member<pVerticalSlider&>, Widget {
|
||||
nall::function<void ()> onChange;
|
||||
|
||||
unsigned position();
|
||||
void setLength(unsigned length);
|
||||
void setPosition(unsigned position);
|
||||
|
||||
VerticalSlider();
|
||||
struct State;
|
||||
State &state;
|
||||
pVerticalSlider &p;
|
||||
};
|
||||
|
||||
struct Viewport : private nall::base_from_member<pViewport&>, Widget {
|
||||
uintptr_t handle();
|
||||
|
||||
Viewport();
|
||||
pViewport &p;
|
||||
};
|
||||
|
||||
#include "layout/fixed-layout.hpp"
|
||||
#include "layout/horizontal-layout.hpp"
|
||||
#include "layout/vertical-layout.hpp"
|
20
bsnes/phoenix/core/layout/fixed-layout.cpp
Executable file
20
bsnes/phoenix/core/layout/fixed-layout.cpp
Executable file
@@ -0,0 +1,20 @@
|
||||
void FixedLayout::setParent(Window &parent) {
|
||||
foreach(child, children) {
|
||||
parent.append(*child.widget);
|
||||
child.widget->setGeometry(child.geometry);
|
||||
}
|
||||
}
|
||||
|
||||
void FixedLayout::append(Widget &widget, const Geometry &geometry) {
|
||||
children.append({ &widget, geometry });
|
||||
}
|
||||
|
||||
void FixedLayout::setGeometry(const Geometry &geometry) {
|
||||
}
|
||||
|
||||
void FixedLayout::setVisible(bool visible) {
|
||||
foreach(child, children) child.widget->setVisible(visible);
|
||||
}
|
||||
|
||||
FixedLayout::FixedLayout() {
|
||||
}
|
15
bsnes/phoenix/core/layout/fixed-layout.hpp
Executable file
15
bsnes/phoenix/core/layout/fixed-layout.hpp
Executable file
@@ -0,0 +1,15 @@
|
||||
struct FixedLayout : Layout {
|
||||
void append(Widget &widget, const Geometry &geometry);
|
||||
void setGeometry(const Geometry &geometry);
|
||||
void setParent(Window &parent);
|
||||
void setVisible(bool visible);
|
||||
FixedLayout();
|
||||
|
||||
//private:
|
||||
Window *parent;
|
||||
struct Children {
|
||||
Widget *widget;
|
||||
Geometry geometry;
|
||||
};
|
||||
nall::linear_vector<Children> children;
|
||||
};
|
139
bsnes/phoenix/core/layout/horizontal-layout.cpp
Executable file
139
bsnes/phoenix/core/layout/horizontal-layout.cpp
Executable file
@@ -0,0 +1,139 @@
|
||||
void HorizontalLayout::append(VerticalLayout &layout, unsigned spacing) {
|
||||
children.append({ &layout, 0, MinimumSize, MinimumSize, spacing });
|
||||
}
|
||||
|
||||
void HorizontalLayout::append(Widget &widget, unsigned width, unsigned height, unsigned spacing) {
|
||||
children.append({ 0, &widget, width, height, spacing });
|
||||
}
|
||||
|
||||
Geometry HorizontalLayout::minimumGeometry() {
|
||||
unsigned width = 0, height = 0;
|
||||
|
||||
foreach(child, children) {
|
||||
width += child.spacing;
|
||||
if(child.width == MinimumSize || child.width == MaximumSize) {
|
||||
if(child.layout) width += child.layout->minimumGeometry().width;
|
||||
if(child.widget) width += child.widget->minimumGeometry().width;
|
||||
continue;
|
||||
}
|
||||
width += child.width;
|
||||
}
|
||||
|
||||
foreach(child, children) {
|
||||
if(child.height == MinimumSize || child.height == MaximumSize) {
|
||||
if(child.layout) height = max(height, child.layout->minimumGeometry().height);
|
||||
if(child.widget) height = max(height, child.widget->minimumGeometry().height);
|
||||
continue;
|
||||
}
|
||||
height = max(height, child.height);
|
||||
}
|
||||
|
||||
return { 0, 0, margin * 2 + width, margin * 2 + height };
|
||||
}
|
||||
|
||||
Geometry HorizontalLayout::minimumLayoutGeometry() {
|
||||
unsigned width = 0, height = 0;
|
||||
bool maximumWidth = false;
|
||||
bool maximumHeight = false;
|
||||
|
||||
foreach(child, children) {
|
||||
if(child.width == MaximumSize) {
|
||||
maximumWidth = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(child.width == MinimumSize) {
|
||||
if(child.layout) width += child.layout->minimumGeometry().width;
|
||||
if(child.widget) width += child.widget->minimumGeometry().width;
|
||||
continue;
|
||||
}
|
||||
|
||||
width += child.width;
|
||||
}
|
||||
|
||||
foreach(child, children) {
|
||||
if(child.height == MaximumSize) {
|
||||
maximumHeight = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(child.height == MinimumSize) {
|
||||
if(child.layout) height = max(height, child.layout->minimumGeometry().height);
|
||||
if(child.widget) height = max(height, child.widget->minimumGeometry().height);
|
||||
continue;
|
||||
}
|
||||
|
||||
height = max(height, child.height);
|
||||
}
|
||||
|
||||
return { 0, 0, maximumWidth ? MaximumSize : margin * 2 + width, maximumHeight ? MaximumSize : margin * 2 + height };
|
||||
}
|
||||
|
||||
void HorizontalLayout::setGeometry(const Geometry &containerGeometry) {
|
||||
auto children = this->children;
|
||||
foreach(child, children) {
|
||||
if(child.layout) {
|
||||
child.width = child.layout->minimumLayoutGeometry().width;
|
||||
child.height = child.layout->minimumLayoutGeometry().height;
|
||||
}
|
||||
|
||||
if(child.widget) {
|
||||
if(child.width == MinimumSize) child.width = child.widget->minimumGeometry().width;
|
||||
if(child.height == MinimumSize) child.height = child.widget->minimumGeometry().height;
|
||||
}
|
||||
}
|
||||
|
||||
Geometry geometry = containerGeometry;
|
||||
geometry.x += margin;
|
||||
geometry.y += margin;
|
||||
geometry.width -= margin * 2;
|
||||
geometry.height -= margin * 2;
|
||||
|
||||
unsigned minimumWidth = 0, maximumWidthCounter = 0;
|
||||
foreach(child, children) {
|
||||
if(child.width == MaximumSize) maximumWidthCounter++;
|
||||
if(child.width != MaximumSize) minimumWidth += child.width;
|
||||
minimumWidth += child.spacing;
|
||||
}
|
||||
|
||||
foreach(child, children) {
|
||||
if(child.width == MaximumSize) child.width = (geometry.width - minimumWidth) / maximumWidthCounter;
|
||||
if(child.height == MaximumSize) child.height = geometry.height;
|
||||
}
|
||||
|
||||
unsigned maximumHeight = 0;
|
||||
foreach(child, children) maximumHeight = max(maximumHeight, child.height);
|
||||
|
||||
foreach(child, children) {
|
||||
unsigned pivot = (maximumHeight - child.height) / 2;
|
||||
Geometry childGeometry = { geometry.x, geometry.y + pivot, child.width, child.height };
|
||||
|
||||
if(child.layout) child.layout->setGeometry(childGeometry);
|
||||
if(child.widget) child.widget->setGeometry(childGeometry);
|
||||
|
||||
geometry.x += child.width + child.spacing;
|
||||
geometry.width -= child.width + child.spacing;
|
||||
}
|
||||
}
|
||||
|
||||
void HorizontalLayout::setMargin(unsigned margin) {
|
||||
this->margin = margin;
|
||||
}
|
||||
|
||||
void HorizontalLayout::setParent(Window &parent) {
|
||||
foreach(child, children) {
|
||||
if(child.layout) child.layout->setParent(parent);
|
||||
if(child.widget) parent.append(*child.widget);
|
||||
}
|
||||
}
|
||||
|
||||
void HorizontalLayout::setVisible(bool visible) {
|
||||
foreach(child, children) {
|
||||
if(child.layout) child.layout->setVisible(visible);
|
||||
if(child.widget) child.widget->setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalLayout::HorizontalLayout() {
|
||||
margin = 0;
|
||||
}
|
22
bsnes/phoenix/core/layout/horizontal-layout.hpp
Executable file
22
bsnes/phoenix/core/layout/horizontal-layout.hpp
Executable file
@@ -0,0 +1,22 @@
|
||||
struct VerticalLayout;
|
||||
|
||||
struct HorizontalLayout : public Layout {
|
||||
void append(VerticalLayout &layout, unsigned spacing = 0);
|
||||
void append(Widget &widget, unsigned width, unsigned height, unsigned spacing = 0);
|
||||
Geometry minimumLayoutGeometry();
|
||||
Geometry minimumGeometry();
|
||||
void setGeometry(const Geometry &geometry);
|
||||
void setMargin(unsigned margin);
|
||||
void setParent(Window &parent);
|
||||
void setVisible(bool visible);
|
||||
HorizontalLayout();
|
||||
|
||||
//private:
|
||||
unsigned margin;
|
||||
struct Children {
|
||||
VerticalLayout *layout;
|
||||
Widget *widget;
|
||||
unsigned width, height, spacing;
|
||||
};
|
||||
nall::linear_vector<Children> children;
|
||||
};
|
139
bsnes/phoenix/core/layout/vertical-layout.cpp
Executable file
139
bsnes/phoenix/core/layout/vertical-layout.cpp
Executable file
@@ -0,0 +1,139 @@
|
||||
void VerticalLayout::append(HorizontalLayout &layout, unsigned spacing) {
|
||||
children.append({ &layout, 0, MinimumSize, MinimumSize, spacing });
|
||||
}
|
||||
|
||||
void VerticalLayout::append(Widget &widget, unsigned width, unsigned height, unsigned spacing) {
|
||||
children.append({ 0, &widget, width, height, spacing });
|
||||
}
|
||||
|
||||
Geometry VerticalLayout::minimumGeometry() {
|
||||
unsigned width = 0, height = 0;
|
||||
|
||||
foreach(child, children) {
|
||||
if(child.width == MinimumSize || child.width == MaximumSize) {
|
||||
if(child.layout) width = max(width, child.layout->minimumGeometry().width);
|
||||
if(child.widget) width = max(width, child.widget->minimumGeometry().width);
|
||||
continue;
|
||||
}
|
||||
width = max(width, child.width);
|
||||
}
|
||||
|
||||
foreach(child, children) {
|
||||
height += child.spacing;
|
||||
if(child.height == MinimumSize || child.height == MaximumSize) {
|
||||
if(child.layout) height += child.layout->minimumGeometry().height;
|
||||
if(child.widget) height += child.widget->minimumGeometry().height;
|
||||
continue;
|
||||
}
|
||||
height += child.height;
|
||||
}
|
||||
|
||||
return { 0, 0, margin * 2 + width, margin * 2 + height };
|
||||
}
|
||||
|
||||
Geometry VerticalLayout::minimumLayoutGeometry() {
|
||||
unsigned width = 0, height = 0;
|
||||
bool maximumWidth = false;
|
||||
bool maximumHeight = false;
|
||||
|
||||
foreach(child, children) {
|
||||
if(child.width == MaximumSize) {
|
||||
maximumWidth = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(child.width == MinimumSize) {
|
||||
if(child.layout) width = max(width, child.layout->minimumGeometry().width);
|
||||
if(child.widget) width = max(width, child.widget->minimumGeometry().width);
|
||||
continue;
|
||||
}
|
||||
|
||||
width = max(width, child.width);
|
||||
}
|
||||
|
||||
foreach(child, children) {
|
||||
if(child.height == MaximumSize) {
|
||||
maximumHeight = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(child.height == MinimumSize) {
|
||||
if(child.layout) height += child.layout->minimumGeometry().height;
|
||||
if(child.widget) height += child.widget->minimumGeometry().height;
|
||||
continue;
|
||||
}
|
||||
|
||||
height += child.height;
|
||||
}
|
||||
|
||||
return { 0, 0, maximumWidth ? MaximumSize : margin * 2 + width, maximumHeight ? MaximumSize : margin * 2 + height };
|
||||
}
|
||||
|
||||
void VerticalLayout::setGeometry(const Geometry &containerGeometry) {
|
||||
auto children = this->children;
|
||||
foreach(child, children) {
|
||||
if(child.layout) {
|
||||
child.width = child.layout->minimumLayoutGeometry().width;
|
||||
child.height = child.layout->minimumLayoutGeometry().height;
|
||||
}
|
||||
|
||||
if(child.widget) {
|
||||
if(child.width == MinimumSize) child.width = child.widget->minimumGeometry().width;
|
||||
if(child.height == MinimumSize) child.height = child.widget->minimumGeometry().height;
|
||||
}
|
||||
}
|
||||
|
||||
Geometry geometry = containerGeometry;
|
||||
geometry.x += margin;
|
||||
geometry.y += margin;
|
||||
geometry.width -= margin * 2;
|
||||
geometry.height -= margin * 2;
|
||||
|
||||
unsigned minimumHeight = 0, maximumHeightCounter = 0;
|
||||
foreach(child, children) {
|
||||
if(child.height == MaximumSize) maximumHeightCounter++;
|
||||
if(child.height != MaximumSize) minimumHeight += child.height;
|
||||
minimumHeight += child.spacing;
|
||||
}
|
||||
|
||||
foreach(child, children) {
|
||||
if(child.width == MaximumSize) child.width = geometry.width;
|
||||
if(child.height == MaximumSize) child.height = (geometry.height - minimumHeight) / maximumHeightCounter;
|
||||
}
|
||||
|
||||
unsigned maximumWidth = 0;
|
||||
foreach(child, children) maximumWidth = max(maximumWidth, child.width);
|
||||
|
||||
foreach(child, children) {
|
||||
unsigned pivot = 0; //(maximumWidth - child.width) / 2;
|
||||
Geometry childGeometry = { geometry.x + pivot, geometry.y, child.width, child.height };
|
||||
|
||||
if(child.layout) child.layout->setGeometry(childGeometry);
|
||||
if(child.widget) child.widget->setGeometry(childGeometry);
|
||||
|
||||
geometry.y += child.height + child.spacing;
|
||||
geometry.height -= child.height + child.spacing;
|
||||
}
|
||||
}
|
||||
|
||||
void VerticalLayout::setMargin(unsigned margin) {
|
||||
this->margin = margin;
|
||||
}
|
||||
|
||||
void VerticalLayout::setParent(Window &parent) {
|
||||
foreach(child, children) {
|
||||
if(child.layout) child.layout->setParent(parent);
|
||||
if(child.widget) parent.append(*child.widget);
|
||||
}
|
||||
}
|
||||
|
||||
void VerticalLayout::setVisible(bool visible) {
|
||||
foreach(child, children) {
|
||||
if(child.layout) child.layout->setVisible(visible);
|
||||
if(child.widget) child.widget->setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
VerticalLayout::VerticalLayout() {
|
||||
margin = 0;
|
||||
}
|
22
bsnes/phoenix/core/layout/vertical-layout.hpp
Executable file
22
bsnes/phoenix/core/layout/vertical-layout.hpp
Executable file
@@ -0,0 +1,22 @@
|
||||
struct HorizontalLayout;
|
||||
|
||||
struct VerticalLayout : public Layout {
|
||||
void append(HorizontalLayout &layout, unsigned spacing = 0);
|
||||
void append(Widget &widget, unsigned width, unsigned height, unsigned spacing = 0);
|
||||
Geometry minimumGeometry();
|
||||
Geometry minimumLayoutGeometry();
|
||||
void setGeometry(const Geometry &geometry);
|
||||
void setMargin(unsigned margin);
|
||||
void setParent(Window &parent);
|
||||
void setVisible(bool visible);
|
||||
VerticalLayout();
|
||||
|
||||
//private:
|
||||
unsigned margin;
|
||||
struct Children {
|
||||
HorizontalLayout *layout;
|
||||
Widget *widget;
|
||||
unsigned width, height, spacing;
|
||||
};
|
||||
nall::linear_vector<Children> children;
|
||||
};
|
252
bsnes/phoenix/core/state.hpp
Executable file
252
bsnes/phoenix/core/state.hpp
Executable file
@@ -0,0 +1,252 @@
|
||||
struct Font::State {
|
||||
bool bold;
|
||||
string family;
|
||||
bool italic;
|
||||
unsigned size;
|
||||
bool underline;
|
||||
|
||||
State() {
|
||||
bold = false;
|
||||
italic = false;
|
||||
size = 8;
|
||||
underline = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Timer::State {
|
||||
bool enabled;
|
||||
unsigned milliseconds;
|
||||
|
||||
State() {
|
||||
enabled = false;
|
||||
milliseconds = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct Window::State {
|
||||
bool backgroundColorOverride;
|
||||
Color backgroundColor;
|
||||
bool fullScreen;
|
||||
Geometry geometry;
|
||||
reference_array<Layout&> layout;
|
||||
reference_array<Menu&> menu;
|
||||
Font *menuFont;
|
||||
bool menuVisible;
|
||||
bool resizable;
|
||||
Font *statusFont;
|
||||
string statusText;
|
||||
bool statusVisible;
|
||||
string title;
|
||||
bool visible;
|
||||
reference_array<Widget&> widget;
|
||||
Font *widgetFont;
|
||||
|
||||
State() {
|
||||
backgroundColorOverride = false;
|
||||
backgroundColor = { 0, 0, 0, 255 };
|
||||
fullScreen = false;
|
||||
geometry = { 128, 128, 256, 256 };
|
||||
menuFont = 0;
|
||||
menuVisible = false;
|
||||
resizable = true;
|
||||
statusVisible = false;
|
||||
visible = false;
|
||||
widgetFont = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct Action::State {
|
||||
bool enabled;
|
||||
Window *parent;
|
||||
bool visible;
|
||||
|
||||
State() {
|
||||
enabled = true;
|
||||
parent = 0;
|
||||
visible = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Menu::State {
|
||||
reference_array<Action&> action;
|
||||
string text;
|
||||
};
|
||||
|
||||
struct Item::State {
|
||||
string text;
|
||||
};
|
||||
|
||||
struct CheckItem::State {
|
||||
bool checked;
|
||||
string text;
|
||||
|
||||
State() {
|
||||
checked = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct RadioItem::State {
|
||||
bool checked;
|
||||
reference_array<RadioItem&> group;
|
||||
string text;
|
||||
|
||||
State() {
|
||||
checked = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Widget::State {
|
||||
bool abstract;
|
||||
bool enabled;
|
||||
Font *font;
|
||||
Geometry geometry;
|
||||
bool visible;
|
||||
|
||||
State() {
|
||||
abstract = false;
|
||||
enabled = true;
|
||||
font = 0;
|
||||
geometry = { 0, 0, 0, 0 };
|
||||
visible = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Button::State {
|
||||
string text;
|
||||
|
||||
State() {
|
||||
}
|
||||
};
|
||||
|
||||
struct CheckBox::State {
|
||||
bool checked;
|
||||
string text;
|
||||
|
||||
State() {
|
||||
checked = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct ComboBox::State {
|
||||
unsigned selection;
|
||||
linear_vector<string> text;
|
||||
|
||||
State() {
|
||||
selection = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct HexEdit::State {
|
||||
unsigned columns;
|
||||
unsigned length;
|
||||
unsigned offset;
|
||||
unsigned rows;
|
||||
|
||||
State() {
|
||||
columns = 16;
|
||||
length = 0;
|
||||
offset = 0;
|
||||
rows = 16;
|
||||
}
|
||||
};
|
||||
|
||||
struct HorizontalScrollBar::State {
|
||||
unsigned length;
|
||||
unsigned position;
|
||||
|
||||
State() {
|
||||
length = 101;
|
||||
position = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct HorizontalSlider::State {
|
||||
unsigned length;
|
||||
unsigned position;
|
||||
|
||||
State() {
|
||||
length = 101;
|
||||
position = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct Label::State {
|
||||
string text;
|
||||
};
|
||||
|
||||
struct LineEdit::State {
|
||||
bool editable;
|
||||
string text;
|
||||
|
||||
State() {
|
||||
editable = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct ListView::State {
|
||||
bool checkable;
|
||||
array<bool> checked;
|
||||
lstring headerText;
|
||||
bool headerVisible;
|
||||
bool selected;
|
||||
unsigned selection;
|
||||
linear_vector<lstring> text;
|
||||
|
||||
State() {
|
||||
checkable = false;
|
||||
headerVisible = false;
|
||||
selected = false;
|
||||
selection = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct ProgressBar::State {
|
||||
unsigned position;
|
||||
|
||||
State() {
|
||||
position = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct RadioBox::State {
|
||||
bool checked;
|
||||
reference_array<RadioBox&> group;
|
||||
string text;
|
||||
|
||||
State() {
|
||||
checked = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct TextEdit::State {
|
||||
unsigned cursorPosition;
|
||||
bool editable;
|
||||
string text;
|
||||
bool wordWrap;
|
||||
|
||||
State() {
|
||||
cursorPosition = 0;
|
||||
editable = true;
|
||||
wordWrap = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct VerticalScrollBar::State {
|
||||
unsigned length;
|
||||
unsigned position;
|
||||
|
||||
State() {
|
||||
length = 101;
|
||||
position = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct VerticalSlider::State {
|
||||
unsigned length;
|
||||
unsigned position;
|
||||
|
||||
State() {
|
||||
length = 101;
|
||||
position = 0;
|
||||
}
|
||||
};
|
22
bsnes/phoenix/gtk/action/action.cpp
Executable file
22
bsnes/phoenix/gtk/action/action.cpp
Executable file
@@ -0,0 +1,22 @@
|
||||
static void Action_setFont(GtkWidget *widget, gpointer font) {
|
||||
if(font == 0) return;
|
||||
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
|
||||
if(GTK_IS_CONTAINER(widget)) {
|
||||
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Action_setFont, (PangoFontDescription*)font);
|
||||
}
|
||||
}
|
||||
|
||||
void pAction::setEnabled(bool enabled) {
|
||||
gtk_widget_set_sensitive(widget, enabled);
|
||||
}
|
||||
|
||||
void pAction::setFont(Font &font) {
|
||||
Action_setFont(widget, font.p.gtkFont);
|
||||
}
|
||||
|
||||
void pAction::setVisible(bool visible) {
|
||||
gtk_widget_set_visible(widget, visible);
|
||||
}
|
||||
|
||||
void pAction::constructor() {
|
||||
}
|
22
bsnes/phoenix/gtk/action/check-item.cpp
Executable file
22
bsnes/phoenix/gtk/action/check-item.cpp
Executable file
@@ -0,0 +1,22 @@
|
||||
static void CheckItem_tick(CheckItem *self) {
|
||||
if(self->p.locked == false && self->onTick) self->onTick();
|
||||
}
|
||||
|
||||
bool pCheckItem::checked() {
|
||||
return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
|
||||
}
|
||||
|
||||
void pCheckItem::setChecked(bool checked) {
|
||||
locked = true;
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), checked);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
void pCheckItem::setText(const string &text) {
|
||||
gtk_menu_item_set_label(GTK_MENU_ITEM(widget), text);
|
||||
}
|
||||
|
||||
void pCheckItem::constructor() {
|
||||
widget = gtk_check_menu_item_new_with_label("");
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(CheckItem_tick), (gpointer)&checkItem);
|
||||
}
|
12
bsnes/phoenix/gtk/action/item.cpp
Executable file
12
bsnes/phoenix/gtk/action/item.cpp
Executable file
@@ -0,0 +1,12 @@
|
||||
static void Item_tick(Item *self) {
|
||||
if(self->onTick) self->onTick();
|
||||
}
|
||||
|
||||
void pItem::setText(const string &text) {
|
||||
gtk_menu_item_set_label(GTK_MENU_ITEM(widget), text);
|
||||
}
|
||||
|
||||
void pItem::constructor() {
|
||||
widget = gtk_menu_item_new_with_label("");
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "activate", G_CALLBACK(Item_tick), (gpointer)&item);
|
||||
}
|
19
bsnes/phoenix/gtk/action/menu.cpp
Executable file
19
bsnes/phoenix/gtk/action/menu.cpp
Executable file
@@ -0,0 +1,19 @@
|
||||
void pMenu::append(Action &action) {
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(submenu), action.p.widget);
|
||||
gtk_widget_show(action.p.widget);
|
||||
}
|
||||
|
||||
void pMenu::setFont(Font &font) {
|
||||
pAction::setFont(font);
|
||||
foreach(item, menu.state.action) item.p.setFont(font);
|
||||
}
|
||||
|
||||
void pMenu::setText(const string &text) {
|
||||
gtk_menu_item_set_label(GTK_MENU_ITEM(widget), text);
|
||||
}
|
||||
|
||||
void pMenu::constructor() {
|
||||
submenu = gtk_menu_new();
|
||||
widget = gtk_menu_item_new_with_label("");
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), submenu);
|
||||
}
|
33
bsnes/phoenix/gtk/action/radio-item.cpp
Executable file
33
bsnes/phoenix/gtk/action/radio-item.cpp
Executable file
@@ -0,0 +1,33 @@
|
||||
static void RadioItem_tick(RadioItem *self) {
|
||||
if(self->p.locked == false && self->checked() && self->onTick) self->onTick();
|
||||
}
|
||||
|
||||
bool pRadioItem::checked() {
|
||||
return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
|
||||
}
|
||||
|
||||
void pRadioItem::setChecked() {
|
||||
locked = true;
|
||||
foreach(item, radioItem.state.group) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item.p.widget), false);
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), true);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
void pRadioItem::setGroup(const reference_array<RadioItem&> &group) {
|
||||
foreach(item, group, n) {
|
||||
if(n == 0) continue;
|
||||
GSList *currentGroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(group[0].p.widget));
|
||||
if(currentGroup != gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item.p.widget))) {
|
||||
gtk_radio_menu_item_set_group(GTK_RADIO_MENU_ITEM(item.p.widget), currentGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pRadioItem::setText(const string &text) {
|
||||
gtk_menu_item_set_label(GTK_MENU_ITEM(widget), text);
|
||||
}
|
||||
|
||||
void pRadioItem::constructor() {
|
||||
widget = gtk_radio_menu_item_new_with_label(0, "");
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(RadioItem_tick), (gpointer)&radioItem);
|
||||
}
|
3
bsnes/phoenix/gtk/action/separator.cpp
Executable file
3
bsnes/phoenix/gtk/action/separator.cpp
Executable file
@@ -0,0 +1,3 @@
|
||||
void pSeparator::constructor() {
|
||||
widget = gtk_separator_menu_item_new();
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
static void Button_tick(Button *self) {
|
||||
if(self->onTick) self->onTick();
|
||||
}
|
||||
|
||||
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_button_new_with_label(text);
|
||||
widget->parent = &parent;
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "clicked", G_CALLBACK(Button_tick), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
static void Canvas_expose(Canvas *self) {
|
||||
uint32_t *rgb = self->canvas->bufferRGB;
|
||||
uint32_t *bgr = self->canvas->bufferBGR;
|
||||
for(unsigned y = self->object->widget->allocation.height; y; y--) {
|
||||
for(unsigned x = self->object->widget->allocation.width; x; x--) {
|
||||
uint32_t pixel = *rgb++;
|
||||
*bgr++ = ((pixel << 16) & 0xff0000) | (pixel & 0x00ff00) | ((pixel >> 16) & 0x0000ff);
|
||||
}
|
||||
}
|
||||
|
||||
gdk_draw_rgb_32_image(
|
||||
self->object->widget->window,
|
||||
self->object->widget->style->fg_gc[GTK_WIDGET_STATE(self->object->widget)],
|
||||
0, 0, self->object->widget->allocation.width, self->object->widget->allocation.height,
|
||||
GDK_RGB_DITHER_NONE, (guchar*)self->canvas->bufferBGR, self->canvas->pitch
|
||||
);
|
||||
}
|
||||
|
||||
void Canvas::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
canvas->bufferRGB = new uint32_t[width * height]();
|
||||
canvas->bufferBGR = new uint32_t[width * height]();
|
||||
canvas->pitch = width * sizeof(uint32_t);
|
||||
|
||||
object->widget = gtk_drawing_area_new();
|
||||
widget->parent = &parent;
|
||||
GdkColor color;
|
||||
color.pixel = color.red = color.green = color.blue = 0;
|
||||
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
|
||||
gtk_widget_set_double_buffered(object->widget, false);
|
||||
gtk_widget_add_events(object->widget, GDK_EXPOSURE_MASK);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
uint32_t* Canvas::buffer() {
|
||||
return canvas->bufferRGB;
|
||||
}
|
||||
|
||||
void Canvas::redraw() {
|
||||
GdkRectangle rect;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = object->widget->allocation.width;
|
||||
rect.height = object->widget->allocation.height;
|
||||
gdk_window_invalidate_rect(object->widget->window, &rect, true);
|
||||
}
|
||||
|
||||
Canvas::Canvas() {
|
||||
canvas = new Canvas::Data;
|
||||
canvas->bufferRGB = 0;
|
||||
canvas->bufferBGR = 0;
|
||||
}
|
||||
|
||||
Canvas::~Canvas() {
|
||||
if(canvas->bufferRGB) delete[] canvas->bufferRGB;
|
||||
if(canvas->bufferBGR) delete[] canvas->bufferBGR;
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
static void CheckBox_tick(CheckBox *self) {
|
||||
if(self->onTick && self->object->locked == false) self->onTick();
|
||||
}
|
||||
|
||||
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_check_button_new_with_label(text);
|
||||
widget->parent = &parent;
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(CheckBox_tick), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
bool CheckBox::checked() {
|
||||
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(object->widget));
|
||||
}
|
||||
|
||||
void CheckBox::setChecked(bool checked) {
|
||||
object->locked = true;
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(object->widget), checked);
|
||||
object->locked = false;
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
void ComboBox_change(ComboBox *self) {
|
||||
if(self->object->locked == false && self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_combo_box_new_text();
|
||||
widget->parent = &parent;
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(ComboBox_change), (gpointer)this);
|
||||
|
||||
if(*text) {
|
||||
lstring list;
|
||||
list.split("\n", text);
|
||||
foreach(item, list) addItem(item);
|
||||
}
|
||||
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void ComboBox::reset() {
|
||||
object->locked = true;
|
||||
for(signed i = counter - 1; i >= 0; i--) {
|
||||
gtk_combo_box_remove_text(GTK_COMBO_BOX(object->widget), i);
|
||||
}
|
||||
object->locked = false;
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
void ComboBox::addItem(const string &text) {
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(object->widget), text);
|
||||
if(counter++ == 0) setSelection(0);
|
||||
}
|
||||
|
||||
unsigned ComboBox::selection() {
|
||||
return gtk_combo_box_get_active(GTK_COMBO_BOX(object->widget));
|
||||
}
|
||||
|
||||
void ComboBox::setSelection(unsigned item) {
|
||||
object->locked = true;
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(object->widget), item);
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
ComboBox::ComboBox() {
|
||||
counter = 0;
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
static void EditBox_change(EditBox *self) {
|
||||
if(self->object->locked == false && self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_scrolled_window_new(0, 0);
|
||||
widget->parent = &parent;
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
object->subWidget = gtk_text_view_new();
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(object->subWidget), GTK_WRAP_WORD_CHAR);
|
||||
gtk_container_add(GTK_CONTAINER(object->widget), object->subWidget);
|
||||
object->textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(object->subWidget));
|
||||
gtk_text_buffer_set_text(object->textBuffer, text, -1);
|
||||
g_signal_connect_swapped(G_OBJECT(object->textBuffer), "changed", G_CALLBACK(EditBox_change), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->subWidget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void EditBox::setFocused() {
|
||||
gtk_widget_grab_focus(object->subWidget);
|
||||
}
|
||||
|
||||
void EditBox::setEditable(bool editable) {
|
||||
gtk_text_view_set_editable(GTK_TEXT_VIEW(object->subWidget), editable);
|
||||
}
|
||||
|
||||
void EditBox::setWordWrap(bool wordWrap) {
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(object->subWidget), wordWrap ? GTK_WRAP_WORD_CHAR : GTK_WRAP_NONE);
|
||||
}
|
||||
|
||||
string EditBox::text() {
|
||||
GtkTextIter start, end;
|
||||
gtk_text_buffer_get_start_iter(object->textBuffer, &start);
|
||||
gtk_text_buffer_get_end_iter(object->textBuffer, &end);
|
||||
char *temp = gtk_text_buffer_get_text(object->textBuffer, &start, &end, true);
|
||||
string text = temp;
|
||||
g_free(temp);
|
||||
return text;
|
||||
}
|
||||
|
||||
void EditBox::setText(const string &text) {
|
||||
object->locked = true;
|
||||
gtk_text_buffer_set_text(object->textBuffer, text, -1);
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
void EditBox::setCursorPosition(unsigned position) {
|
||||
GtkTextMark *mark = gtk_text_buffer_get_mark(object->textBuffer, "insert");
|
||||
GtkTextIter iter;
|
||||
gtk_text_buffer_get_end_iter(object->textBuffer, &iter);
|
||||
gtk_text_iter_set_offset(&iter, min(position, gtk_text_iter_get_offset(&iter)));
|
||||
gtk_text_buffer_place_cursor(object->textBuffer, &iter);
|
||||
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(object->subWidget), mark);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user