mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-26 18:40:47 +00:00
Update to v106r65 release.
byuu says: This synchronizes bsnes/higan with many recent internal nall changes. This will be the last WIP until I am situated in Japan. Apologies for the bugfixes that didn't get applied yet, I ran out of time.
This commit is contained in:
parent
336d20123f
commit
03b06257d3
@ -55,3 +55,5 @@ else ifneq ($(filter $(platform),linux bsd),)
|
||||
rm -f $(prefix)/share/applications/$(name).desktop
|
||||
rm -f $(prefix)/share/icons/$(name).png
|
||||
endif
|
||||
|
||||
-include obj/*.d
|
||||
|
@ -148,7 +148,7 @@ auto ListWindow::loadDatabase(string location) -> void {
|
||||
}
|
||||
|
||||
auto ListWindow::saveDatabase(string location) -> void {
|
||||
file fp{location, file::mode::write};
|
||||
auto fp = file::open(location, file::mode::write);
|
||||
if(!fp) return MessageDialog().setParent(*this).setText({
|
||||
"Error: failed to write file.\n\n",
|
||||
"Name: ", location
|
||||
@ -618,24 +618,12 @@ auto hiro::initialize() -> void {
|
||||
}
|
||||
|
||||
#include <nall/main.hpp>
|
||||
auto nall::main(vector<string> arguments) -> void {
|
||||
auto nall::main(Arguments) -> void {
|
||||
new ListWindow;
|
||||
new GameWindow;
|
||||
new MemoryWindow;
|
||||
new OscillatorWindow;
|
||||
|
||||
//internal command used to synchronize all genius databases from an old format to a new format
|
||||
//if enabled, use with extreme caution and make backups first
|
||||
/*if(arguments.size() == 3 && arguments[1] == "--sync") {
|
||||
for(auto& filename : directory::contents(arguments[2], "*.bml")) {
|
||||
if(filename.beginsWith("Boards")) continue;
|
||||
print(filename, "\n");
|
||||
listWindow->loadDatabase({arguments[2], filename});
|
||||
listWindow->saveDatabase({arguments[2], filename});
|
||||
}
|
||||
return print("[Done]\n");
|
||||
}*/
|
||||
|
||||
listWindow->setVisible();
|
||||
Application::run();
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ using namespace nall;
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "106.64";
|
||||
static const string Version = "106.65";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
@ -67,7 +67,7 @@ auto APU::power() -> void {
|
||||
phase = 0;
|
||||
cycle = 0;
|
||||
|
||||
PRNG prng;
|
||||
PRNG::PCG prng;
|
||||
for(auto& n : wave.pattern) n = prng.random();
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ auto BSMemory::load() -> bool {
|
||||
for(auto& byte : page.buffer[1]) byte = random();
|
||||
|
||||
for(auto& block : blocks) {
|
||||
block.erased = 0;
|
||||
block.erased = 1;
|
||||
block.locked = 1;
|
||||
}
|
||||
|
||||
|
@ -23,10 +23,9 @@ auto hiro::initialize() -> void {
|
||||
}
|
||||
|
||||
#include <nall/main.hpp>
|
||||
auto nall::main(vector<string> arguments) -> void {
|
||||
auto nall::main(Arguments arguments) -> void {
|
||||
settings.location = locate("settings.bml");
|
||||
|
||||
arguments.takeLeft(); //ignore program location in argument parsing
|
||||
for(auto argument : arguments) {
|
||||
if(argument == "--fullscreen") {
|
||||
presentation.startFullScreen = true;
|
||||
|
@ -123,7 +123,7 @@ auto Program::openRomSuperFamicom(string name, vfs::file::mode mode) -> vfs::sha
|
||||
return vfs::fs::file::open({Location::notsuffix(superFamicom.location), ".msu"}, mode);
|
||||
}
|
||||
|
||||
if(name.match("msu1/track-*.pcm")) {
|
||||
if(name.match("msu1/track*.pcm")) {
|
||||
name.trimLeft("msu1/track", 1L);
|
||||
return vfs::fs::file::open({Location::notsuffix(superFamicom.location), name}, mode);
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ auto Program::saveState(string filename) -> bool {
|
||||
if(gamePath().endsWith("/")) {
|
||||
string location = {statePath(), filename, ".bst"};
|
||||
directory::create(Location::path(location));
|
||||
if(!file::write(location, saveState.data(), saveState.size())) {
|
||||
if(!file::write(location, saveState)) {
|
||||
return showMessage({"Unable to write [", prefix, "] to disk"}), false;
|
||||
}
|
||||
} else {
|
||||
|
@ -18,7 +18,7 @@ auto hiro::initialize() -> void {
|
||||
}
|
||||
|
||||
#include <nall/main.hpp>
|
||||
auto nall::main(vector<string> arguments) -> void {
|
||||
auto nall::main(Arguments arguments) -> void {
|
||||
new Program(arguments);
|
||||
Application::run();
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
#include <nall/nall.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <ruby/ruby.hpp>
|
||||
using namespace ruby;
|
||||
extern unique_pointer<Video> video;
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "utility.cpp"
|
||||
unique_pointer<Program> program;
|
||||
|
||||
Program::Program(vector<string> arguments) {
|
||||
Program::Program(Arguments arguments) {
|
||||
program = this;
|
||||
|
||||
Emulator::platform = this;
|
||||
@ -89,8 +89,7 @@ Program::Program(vector<string> arguments) {
|
||||
updateAudioDriver();
|
||||
updateAudioEffects();
|
||||
|
||||
arguments.takeFirst(); //ignore program location in argument parsing
|
||||
for(auto& argument : arguments) {
|
||||
for(auto argument : arguments) {
|
||||
if(argument == "--fullscreen") {
|
||||
presentation->toggleFullScreen();
|
||||
} else if(directory::exists(argument.split("|", 1L).right())) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
struct Program : Emulator::Platform {
|
||||
//program.cpp
|
||||
Program(vector<string> arguments);
|
||||
Program(Arguments arguments);
|
||||
auto main() -> void;
|
||||
auto quit() -> void;
|
||||
|
||||
|
@ -11,9 +11,9 @@ auto Program::loadState(uint slot, bool managed) -> bool {
|
||||
string type = managed ? "managed" : "quick";
|
||||
auto location = stateName(slot, managed);
|
||||
auto memory = file::read(location);
|
||||
if(memory.size() == 0) return showMessage({"Slot ", slot, " ", type, " state does not exist"}), false;
|
||||
if(!memory) return showMessage({"Slot ", slot, " ", type, " state does not exist"}), false;
|
||||
serializer s(memory.data(), memory.size());
|
||||
if(emulator->unserialize(s) == false) return showMessage({"Slot ", slot, " ", type, " state incompatible"}), false;
|
||||
if(!emulator->unserialize(s)) return showMessage({"Slot ", slot, " ", type, " state incompatible"}), false;
|
||||
return showMessage({"Loaded ", type, " state from slot ", slot}), true;
|
||||
}
|
||||
|
||||
@ -22,10 +22,8 @@ auto Program::saveState(uint slot, bool managed) -> bool {
|
||||
string type = managed ? "managed" : "quick";
|
||||
auto location = stateName(slot, managed);
|
||||
serializer s = emulator->serialize();
|
||||
if(s.size() == 0) return showMessage({"Failed to save ", type, " state to slot ", slot}), false;
|
||||
if(!s) return showMessage({"Failed to save ", type, " state to slot ", slot}), false;
|
||||
directory::create(Location::path(location));
|
||||
if(file::write(location, s.data(), s.size()) == false) {
|
||||
return showMessage({"Unable to write ", type, " state to slot ", slot}), false;
|
||||
}
|
||||
if(!file::write(location, {s.data(), s.size()})) return showMessage({"Unable to write ", type, " state to slot ", slot}), false;
|
||||
return showMessage({"Saved ", type, " state to slot ", slot}), true;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
database
|
||||
revision: 2018-05-17
|
||||
revision: 2018-09-20
|
||||
|
||||
//BS Memory (JPN)
|
||||
|
@ -1,5 +1,5 @@
|
||||
database
|
||||
revision: 2018-05-17
|
||||
revision: 2018-09-20
|
||||
|
||||
//Sufami Turbo (JPN)
|
||||
|
@ -1,5 +1,5 @@
|
||||
database
|
||||
revision: 2018-05-17
|
||||
revision: 2018-09-20
|
||||
|
||||
//Prototypes (JPN)
|
||||
|
||||
@ -125,7 +125,7 @@ game
|
||||
//Super Famicom (JPN)
|
||||
|
||||
database
|
||||
revision: 2018-05-17
|
||||
revision: 2018-09-20
|
||||
|
||||
game
|
||||
sha256: 5c4e283efc338958b8dd45ebd6daf133a9eb280420a98e2e1df358ae0242c366
|
||||
@ -1002,6 +1002,18 @@ game
|
||||
content: Program
|
||||
note: Custom wiring on PCB
|
||||
|
||||
game
|
||||
sha256: 76f80cdf704a0e1daf1af5bbf564e427b425a5ee42329417de6f29219fe63e5f
|
||||
label: ロックマンエックス
|
||||
name: Rockman X
|
||||
region: SHVC-RX
|
||||
revision: SHVC-RX-1
|
||||
board: SHVC-2A0N-11
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x180000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 6dfc016c571a16e5d42045060b1a88b6f3da5831e05b33c22035e1d990deccf3
|
||||
label: ロマンシング サ・ガ3 体験版サンプルROM
|
||||
@ -1321,6 +1333,22 @@ game
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: b3204162def67b0dc40097344074e9b660ed296e5b5e22e778f373f0b985645b
|
||||
label: スーパー麻雀大会
|
||||
name: Super Mahjong Taikai
|
||||
region: SHVC-IQ
|
||||
revision: SHVC-IQ-2
|
||||
board: SHVC-1A3B-13
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x80000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: 15d1187d17fa10c77152f691197d33674e64c33a1f8ceb37e8570588be507b89
|
||||
label: スーパー麻雀大会
|
||||
@ -5733,7 +5761,7 @@ game
|
||||
//Super Nintendo (USA)
|
||||
|
||||
database
|
||||
revision: 2018-05-06
|
||||
revision: 2018-09-20
|
||||
|
||||
game
|
||||
sha256: 2ffe8828480f943056fb1ab5c3c84d48a0bf8cbe3ed7c9960b349b59adb07f3b
|
||||
@ -7538,6 +7566,22 @@ game
|
||||
oscillator
|
||||
frequency: 21440000
|
||||
|
||||
game
|
||||
sha256: fa8cacf5bbfc39ee6bbaa557adf89133d60d42f6cf9e1db30d5a36a469f74d15
|
||||
label: Donkey Kong Country
|
||||
name: Donkey Kong Country
|
||||
region: SNS-8X-USA
|
||||
revision: SNS-8X-0
|
||||
board: SHVC-1J1M-11
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x400000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x800
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: df2644d435330192a13768cc1f79c5aa3084a64217a5250c6dd4ffdbe2175be4
|
||||
label: Donkey Kong Country
|
||||
@ -10270,6 +10314,18 @@ game
|
||||
size: 0x180000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: b8f70a6e7fb93819f79693578887e2c11e196bdf1ac6ddc7cb924b1ad0be2d32
|
||||
label: Mega Man X
|
||||
name: Mega Man X
|
||||
region: SNS-RX-USA
|
||||
revision: SNS-RX-1
|
||||
board: MAXI-1A0N-30
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x180000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: da484f2a636b8d692840f40e5468e992c5f2af26d365c69fbc12ef2923588d23
|
||||
label: Mega Man X2
|
||||
@ -12980,6 +13036,23 @@ game
|
||||
content: Save
|
||||
volatile
|
||||
|
||||
game
|
||||
sha256: 82e39dfbb3e4fe5c28044e80878392070c618b298dd5a267e5ea53c8f72cc548
|
||||
label: Star Fox
|
||||
name: Star Fox
|
||||
region: SNS-FO-USA
|
||||
revision: SNS-FO-2
|
||||
board: SHVC-1C0N
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x100000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x8000
|
||||
content: Save
|
||||
volatile
|
||||
|
||||
game
|
||||
sha256: 2c0bac12a7866fad1cb306da768a201c12f2520332df1ef51cba1576db21ff06
|
||||
label: Star Fox: Super Weekend
|
||||
@ -13690,6 +13763,46 @@ game
|
||||
oscillator
|
||||
frequency: 7600000
|
||||
|
||||
game
|
||||
sha256: 76d293e5a772eb2f326e173eac62ca323873b1f329f9b935a97ba86974e1fcd5
|
||||
label: Super Mario Kart
|
||||
name: Super Mario Kart
|
||||
region: SNS-MK-USA
|
||||
revision: SNS-MK-0
|
||||
board: SHVC-1K1X-10
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x80000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x800
|
||||
content: Save
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x1800
|
||||
content: Program
|
||||
manufacturer: NEC
|
||||
architecture: uPD7725
|
||||
identifier: DSP1B
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x800
|
||||
content: Data
|
||||
manufacturer: NEC
|
||||
architecture: uPD7725
|
||||
identifier: DSP1B
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x200
|
||||
content: Data
|
||||
manufacturer: NEC
|
||||
architecture: uPD7725
|
||||
identifier: DSP1B
|
||||
volatile
|
||||
oscillator
|
||||
frequency: 7600000
|
||||
|
||||
game
|
||||
sha256: 740646f3535bfb365ca44e70d46ab433467b142bd84010393070bd0b141af853
|
||||
label: Super Mario RPG: Legend of the Seven Stars
|
||||
@ -13727,6 +13840,24 @@ game
|
||||
size: 0x800
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: 9b4957466798bbdb5b43a450bbb60b2591ae81d95b891430f62d53ca62e8bc7b
|
||||
label: Super Mario World 2: Yoshi's Island
|
||||
name: Super Mario World 2 - Yoshi's Island
|
||||
region: SNS-YI-USA
|
||||
revision: SNS-YI-0
|
||||
board: SHVC-1CB5B-01
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x200000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x8000
|
||||
content: Save
|
||||
oscillator
|
||||
frequency: 21440000
|
||||
|
||||
game
|
||||
sha256: bd763c1a56365c244be92e6cffefd318780a2a19eda7d5baf1c6d5bd6c1b3e06
|
||||
label: Super Mario World 2: Yoshi's Island
|
@ -42,13 +42,13 @@ else ifneq ($(filter $(platform),linux bsd),)
|
||||
mkdir -p $(prefix)/share/applications/
|
||||
mkdir -p $(prefix)/share/icons/
|
||||
mkdir -p $(prefix)/share/$(name)/
|
||||
mkdir -p $(prefix)/share/$(name)/database/
|
||||
mkdir -p $(prefix)/share/$(name)/firmware/
|
||||
mkdir -p $(prefix)/share/$(name)/Database/
|
||||
mkdir -p $(prefix)/share/$(name)/Firmware/
|
||||
cp out/$(name) $(prefix)/bin/$(name)
|
||||
cp data/$(name).desktop $(prefix)/share/applications/$(name).desktop
|
||||
cp data/$(name).png $(prefix)/share/icons/$(name).png
|
||||
cp -R database/* $(prefix)/share/$(name)/database/
|
||||
cp -R firmware/* $(prefix)/share/$(name)/firmware/
|
||||
cp -R Database/* $(prefix)/share/$(name)/Database/
|
||||
cp -R Firmware/* $(prefix)/share/$(name)/Firmware/
|
||||
endif
|
||||
|
||||
uninstall:
|
||||
|
@ -1,19 +1,19 @@
|
||||
Icarus::Icarus() {
|
||||
Database::Famicom = BML::unserialize(string::read(locate("database/Famicom.bml")));
|
||||
Database::SuperFamicom = BML::unserialize(string::read(locate("database/Super Famicom.bml")));
|
||||
Database::MasterSystem = BML::unserialize(string::read(locate("database/Master System.bml")));
|
||||
Database::MegaDrive = BML::unserialize(string::read(locate("database/Mega Drive.bml")));
|
||||
Database::PCEngine = BML::unserialize(string::read(locate("database/PC Engine.bml")));
|
||||
Database::SuperGrafx = BML::unserialize(string::read(locate("database/SuperGrafx.bml")));
|
||||
Database::GameBoy = BML::unserialize(string::read(locate("database/Game Boy.bml")));
|
||||
Database::GameBoyColor = BML::unserialize(string::read(locate("database/Game Boy Color.bml")));
|
||||
Database::GameBoyAdvance = BML::unserialize(string::read(locate("database/Game Boy Advance.bml")));
|
||||
Database::GameGear = BML::unserialize(string::read(locate("database/Game Gear.bml")));
|
||||
Database::WonderSwan = BML::unserialize(string::read(locate("database/WonderSwan.bml")));
|
||||
Database::WonderSwanColor = BML::unserialize(string::read(locate("database/WonderSwan Color.bml")));
|
||||
Database::PocketChallengeV2 = BML::unserialize(string::read(locate("database/Pocket Challenge V2.bml")));
|
||||
Database::BSMemory = BML::unserialize(string::read(locate("database/BS Memory.bml")));
|
||||
Database::SufamiTurbo = BML::unserialize(string::read(locate("database/Sufami Turbo.bml")));
|
||||
Database::Famicom = BML::unserialize(string::read(locate("Database/Famicom.bml")));
|
||||
Database::SuperFamicom = BML::unserialize(string::read(locate("Database/Super Famicom.bml")));
|
||||
Database::MasterSystem = BML::unserialize(string::read(locate("Database/Master System.bml")));
|
||||
Database::MegaDrive = BML::unserialize(string::read(locate("Database/Mega Drive.bml")));
|
||||
Database::PCEngine = BML::unserialize(string::read(locate("Database/PC Engine.bml")));
|
||||
Database::SuperGrafx = BML::unserialize(string::read(locate("Database/SuperGrafx.bml")));
|
||||
Database::GameBoy = BML::unserialize(string::read(locate("Database/Game Boy.bml")));
|
||||
Database::GameBoyColor = BML::unserialize(string::read(locate("Database/Game Boy Color.bml")));
|
||||
Database::GameBoyAdvance = BML::unserialize(string::read(locate("Database/Game Boy Advance.bml")));
|
||||
Database::GameGear = BML::unserialize(string::read(locate("Database/Game Gear.bml")));
|
||||
Database::WonderSwan = BML::unserialize(string::read(locate("Database/WonderSwan.bml")));
|
||||
Database::WonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.bml")));
|
||||
Database::PocketChallengeV2 = BML::unserialize(string::read(locate("Database/Pocket Challenge V2.bml")));
|
||||
Database::BSMemory = BML::unserialize(string::read(locate("Database/BS Memory.bml")));
|
||||
Database::SufamiTurbo = BML::unserialize(string::read(locate("Database/Sufami Turbo.bml")));
|
||||
}
|
||||
|
||||
auto Icarus::error() const -> string {
|
||||
|
@ -12,7 +12,7 @@ struct Icarus {
|
||||
}
|
||||
|
||||
virtual auto write(const string& filename, const uint8_t* data, uint size) -> bool {
|
||||
return file::write(filename, data, size);
|
||||
return file::write(filename, {data, size});
|
||||
}
|
||||
|
||||
auto write(const string& filename, const vector<uint8_t>& buffer) -> bool {
|
||||
|
@ -46,7 +46,7 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, string location) -> str
|
||||
auto size = rom["size"].natural();
|
||||
if(size > buffer.size() - offset) {
|
||||
auto firmware = string{rom["identifier"].text(), ".", rom["content"].text(), ".rom"}.trimLeft(".", 1L).downcase();
|
||||
auto location = locate({"firmware/", firmware});
|
||||
auto location = locate({"Firmware/", firmware});
|
||||
if(location && file::size(location) == size) {
|
||||
write({target, name}, file::read(location));
|
||||
} else {
|
||||
|
@ -62,23 +62,23 @@ auto hiro::initialize() -> void {
|
||||
}
|
||||
|
||||
#include <nall/main.hpp>
|
||||
auto nall::main(vector<string> arguments) -> void {
|
||||
if(arguments.size() == 2 && arguments[1] == "--name") {
|
||||
auto nall::main(Arguments arguments) -> void {
|
||||
if(arguments.size() == 1 && arguments[0] == "--name") {
|
||||
return print("icarus");
|
||||
}
|
||||
|
||||
if(arguments.size() == 3 && arguments[1] == "--manifest" && directory::exists(arguments[2])) {
|
||||
return print(icarus.manifest(arguments[2]));
|
||||
if(arguments.size() == 2 && arguments[0] == "--manifest" && directory::exists(arguments[1])) {
|
||||
return print(icarus.manifest(arguments[1]));
|
||||
}
|
||||
|
||||
if(arguments.size() == 3 && arguments[1] == "--import" && file::exists(arguments[2])) {
|
||||
if(string target = icarus.import(arguments[2])) {
|
||||
if(arguments.size() == 2 && arguments[0] == "--import" && file::exists(arguments[1])) {
|
||||
if(string target = icarus.import(arguments[1])) {
|
||||
return print(target, "\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(arguments.size() == 2 && arguments[1] == "--import") {
|
||||
if(arguments.size() == 1 && arguments[0] == "--import") {
|
||||
if(string source = BrowserDialog()
|
||||
.setTitle("Load ROM File")
|
||||
.setPath(settings["icarus/Path"].text())
|
||||
|
@ -39,10 +39,13 @@ ifeq ($(platform),)
|
||||
endif
|
||||
endif
|
||||
|
||||
compiler.c = $(compiler) -x c -std=c11
|
||||
compiler.cpp = $(compiler) -x c++ -std=c++14
|
||||
compiler.objc = $(compiler) -x objective-c -std=c11
|
||||
compiler.objcpp = $(compiler) -x objective-c++ -std=c++14
|
||||
|
||||
flags.c = -x c -std=c11
|
||||
flags.h = -x c-header -std=c11
|
||||
flags.cpp = -x c++ -std=c++14
|
||||
flags.hpp = -x c++-header -std=c++14
|
||||
flags.objc = -x objective-c -std=c11
|
||||
flags.objcpp = -x objective-c++ -std=c++14
|
||||
flags.deps = -MMD -MP -MF $(@:.o=.d)
|
||||
@ -51,8 +54,8 @@ flags.deps = -MMD -MP -MF $(@:.o=.d)
|
||||
ifeq ($(compiler),)
|
||||
ifeq ($(platform),windows)
|
||||
compiler := g++
|
||||
flags.cpp := -x c++ -std=gnu++14
|
||||
flags.hpp := -x c++-header -std=gnu++14
|
||||
compiler.cpp = $(compiler) -x c++ -std=gnu++14
|
||||
flags.cpp = -x c++ -std=gnu++14
|
||||
else ifeq ($(platform),macos)
|
||||
compiler := clang++
|
||||
else ifeq ($(platform),linux)
|
||||
@ -158,14 +161,10 @@ nall.verbose:
|
||||
compile = \
|
||||
$(strip \
|
||||
$(if $(filter %.c,$<), \
|
||||
$(compiler) $(flags.c) $(flags.deps) $(flags) $1 -c $< -o $@ \
|
||||
$(compiler.c) $(flags.deps) $(flags) $1 -c $< -o $@ \
|
||||
,$(if $(filter %.cpp,$<), \
|
||||
$(compiler) $(flags.cpp) $(flags.deps) $(flags) $1 -c $< -o $@ \
|
||||
,$(if $(filter %.h,$<), \
|
||||
$(compiler) $(flags.h) $(flags) $1 -c $< -o $@ \
|
||||
,$(if $(filter %.hpp,$<), \
|
||||
$(compiler) $(flags.hpp) $(flags) $1 -c $< -o $@ \
|
||||
)))) \
|
||||
$(compiler.cpp) $(flags.deps) $(flags) $1 -c $< -o $@ \
|
||||
)) \
|
||||
)
|
||||
|
||||
# function rwildcard(directory, pattern)
|
||||
|
161
nall/arguments.hpp
Normal file
161
nall/arguments.hpp
Normal file
@ -0,0 +1,161 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/location.hpp>
|
||||
#include <nall/path.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct Arguments {
|
||||
Arguments(int argc, char** argv);
|
||||
Arguments(vector<string> arguments);
|
||||
|
||||
explicit operator bool() const { return (bool)arguments; }
|
||||
auto size() const -> uint { return arguments.size(); }
|
||||
|
||||
auto operator[](uint index) -> string& { return arguments[index]; }
|
||||
auto operator[](uint index) const -> const string& { return arguments[index]; }
|
||||
|
||||
auto programPath() const -> string;
|
||||
auto programName() const -> string;
|
||||
auto programLocation() const -> string;
|
||||
|
||||
auto find(string_view name) const -> bool;
|
||||
auto find(string_view name, bool& argument) const -> bool;
|
||||
auto find(string_view name, string& argument) const -> bool;
|
||||
|
||||
auto begin() const { return arguments.begin(); }
|
||||
auto end() const { return arguments.end(); }
|
||||
|
||||
auto rbegin() const { return arguments.rbegin(); }
|
||||
auto rend() const { return arguments.rend(); }
|
||||
|
||||
auto take() -> string;
|
||||
auto take(string_view name) -> bool;
|
||||
auto take(string_view name, bool& argument) -> bool;
|
||||
auto take(string_view name, string& argument) -> bool;
|
||||
|
||||
auto begin() { return arguments.begin(); }
|
||||
auto end() { return arguments.end(); }
|
||||
|
||||
auto rbegin() { return arguments.rbegin(); }
|
||||
auto rend() { return arguments.rend(); }
|
||||
|
||||
private:
|
||||
auto construct() -> void;
|
||||
|
||||
string programArgument;
|
||||
vector<string> arguments;
|
||||
};
|
||||
|
||||
inline auto Arguments::construct() -> void {
|
||||
if(!arguments) return;
|
||||
|
||||
//extract and pre-process program argument
|
||||
programArgument = arguments.takeFirst();
|
||||
programArgument = {Path::real(programArgument), Location::file(programArgument)};
|
||||
|
||||
//normalize path and file arguments
|
||||
for(auto& argument : arguments) {
|
||||
if(directory::exists(argument)) argument.transform("\\", "/").trimRight("/").append("/");
|
||||
else if(file::exists(argument)) argument.transform("\\", "/").trimRight("/");
|
||||
}
|
||||
}
|
||||
|
||||
inline Arguments::Arguments(int argc, char** argv) {
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
utf8_arguments(argc, argv);
|
||||
#endif
|
||||
for(uint index : range(argc)) arguments.append(argv[index]);
|
||||
construct();
|
||||
}
|
||||
|
||||
inline Arguments::Arguments(vector<string> arguments) {
|
||||
this->arguments = arguments;
|
||||
construct();
|
||||
}
|
||||
|
||||
inline auto Arguments::programPath() const -> string {
|
||||
return Location::path(programArgument);
|
||||
}
|
||||
|
||||
inline auto Arguments::programName() const -> string {
|
||||
return Location::file(programArgument);
|
||||
}
|
||||
|
||||
inline auto Arguments::programLocation() const -> string {
|
||||
return programArgument;
|
||||
}
|
||||
|
||||
inline auto Arguments::find(string_view name) const -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline auto Arguments::find(string_view name, bool& argument) const -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name) && arguments.size() >= index
|
||||
&& (arguments[index + 1] == "true" || arguments[index + 1] == "false")) {
|
||||
argument = arguments[index + 1] == "true";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline auto Arguments::find(string_view name, string& argument) const -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name) && arguments.size() >= index) {
|
||||
argument = arguments[index + 1];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline auto Arguments::take() -> string {
|
||||
if(!arguments) return {};
|
||||
return arguments.takeFirst();
|
||||
}
|
||||
|
||||
inline auto Arguments::take(string_view name) -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name)) {
|
||||
arguments.remove(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline auto Arguments::take(string_view name, bool& argument) -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name) && arguments.size() >= index
|
||||
&& (arguments[index + 1] == "true" || arguments[index + 1] == "false")) {
|
||||
arguments.remove(index);
|
||||
argument = arguments.take(index) == "true";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline auto Arguments::take(string_view name, string& argument) -> bool {
|
||||
for(uint index : range(arguments.size())) {
|
||||
if(arguments[index].match(name) && arguments.size() >= index) {
|
||||
arguments.remove(index);
|
||||
argument = arguments.take(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -10,7 +10,18 @@
|
||||
|
||||
#include <nall/arithmetic/unsigned.hpp>
|
||||
|
||||
#if !defined(__SIZEOF_INT128__)
|
||||
namespace nall {
|
||||
template<uint Bits> struct ArithmeticNatural;
|
||||
template<> struct ArithmeticNatural< 8> { using type = uint8_t; };
|
||||
template<> struct ArithmeticNatural< 16> { using type = uint16_t; };
|
||||
template<> struct ArithmeticNatural< 32> { using type = uint32_t; };
|
||||
template<> struct ArithmeticNatural< 64> { using type = uint64_t; };
|
||||
#if INTMAX_BITS >= 128
|
||||
template<> struct ArithmeticNatural<128> { using type = uint128_t; };
|
||||
#endif
|
||||
}
|
||||
|
||||
#if INTMAX_BITS < 128
|
||||
#define PairBits 128
|
||||
#define TypeBits 64
|
||||
#define HalfBits 32
|
||||
|
@ -2,20 +2,27 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct BarrettReduction {
|
||||
BarrettReduction(uint256_t modulo) : modulo(modulo), factor((1_u1024 << 512) / modulo) {}
|
||||
template<uint Bits> struct BarrettReduction {
|
||||
using type = typename ArithmeticNatural<1 * Bits>::type;
|
||||
using pair = typename ArithmeticNatural<2 * Bits>::type;
|
||||
|
||||
//return = value % modulo
|
||||
inline auto operator()(uint512_t value) const -> uint256_t {
|
||||
uint512_t hi, lo;
|
||||
nall::mul(value, factor, hi, lo);
|
||||
uint512_t remainder = value - hi * modulo;
|
||||
explicit BarrettReduction(type modulo) : modulo(modulo), factor(pair(1) + -pair(modulo) / modulo) {}
|
||||
|
||||
//return => value % modulo
|
||||
inline auto operator()(pair value) const -> type {
|
||||
pair hi, lo;
|
||||
mul(value, factor, hi, lo);
|
||||
pair remainder = value - hi * modulo;
|
||||
return remainder < modulo ? remainder : remainder - modulo;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint512_t modulo;
|
||||
const uint512_t factor;
|
||||
const pair modulo;
|
||||
const pair factor;
|
||||
};
|
||||
|
||||
template<typename T, uint Bits> auto operator%(T value, const BarrettReduction<Bits>& modulo) {
|
||||
return modulo(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ struct Pair {
|
||||
explicit operator bool() const { return hi | lo; }
|
||||
template<typename T> operator T() const { T value; _get(*this, value); return value; }
|
||||
|
||||
auto operator+() const -> Pair { return *this; }
|
||||
auto operator-() const -> Pair { return Pair(0) - *this; }
|
||||
auto operator~() const -> Pair { return {~hi, ~lo}; }
|
||||
auto operator!() const -> bool { return !(hi || lo); }
|
||||
|
||||
@ -75,13 +77,6 @@ struct Pair {
|
||||
template<typename T> auto operator> (const T& rhs) const -> bool { return Cast(*this) > Cast(rhs); }
|
||||
template<typename T> auto operator< (const T& rhs) const -> bool { return Cast(*this) < Cast(rhs); }
|
||||
|
||||
explicit Pair(const vector<uint8_t>& value) : hi(0), lo(0) {
|
||||
for(auto n : reverse(value)) {
|
||||
operator<<=(8);
|
||||
operator|=(n);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Type lo;
|
||||
Type hi;
|
||||
@ -98,6 +93,10 @@ private:
|
||||
template<typename T> friend auto shr(const Pair&, const T&) -> Pair;
|
||||
};
|
||||
|
||||
template<> struct ArithmeticNatural<PairBits> {
|
||||
using type = Pair;
|
||||
};
|
||||
|
||||
#define ConcatenateUDL(Size) _u##Size
|
||||
#define DeclareUDL(Size) ConcatenateUDL(Size)
|
||||
|
||||
@ -333,29 +332,6 @@ template<> struct stringify<Pair> {
|
||||
uint _size;
|
||||
};
|
||||
|
||||
inline auto to_vector(Pair value) -> vector<uint8_t> {
|
||||
vector<uint8_t> result;
|
||||
result.resize(PairBits / 8);
|
||||
for(auto& byte : result) {
|
||||
byte = value;
|
||||
value >>= 8;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
inline auto hex(const Pair& value, long precision = 0, char padchar = '0') -> string {
|
||||
string text;
|
||||
if(!upper(value)) {
|
||||
text.append(hex(lower(value)));
|
||||
} else {
|
||||
text.append(hex(upper(value)));
|
||||
text.append(hex(lower(value), TypeBits / 4, '0'));
|
||||
}
|
||||
return pad(text, precision, padchar);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#undef ConcatenateType
|
||||
|
@ -2,25 +2,35 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename T, enable_if_t<is_unsigned<T>::value>> alwaysinline auto upper(T value) -> T {
|
||||
template<typename T, enable_if_t<is_unsigned<T>::value>>
|
||||
inline auto upper(T value) -> T {
|
||||
return value >> sizeof(T) * 4;
|
||||
}
|
||||
|
||||
template<typename T, enable_if_t<is_unsigned<T>::value>> alwaysinline auto lower(T value) -> T {
|
||||
static const T Mask = T(0) - 1 >> sizeof(T) * 4;
|
||||
template<typename T, enable_if_t<is_unsigned<T>::value>>
|
||||
inline auto lower(T value) -> T {
|
||||
static const T Mask = ~T(0) >> sizeof(T) * 4;
|
||||
return value & Mask;
|
||||
}
|
||||
|
||||
alwaysinline auto square(uintmax value) -> uintmax {
|
||||
template<typename T, typename U, enable_if_t<is_unsigned<T>::value>, enable_if_t<is_unsigned<U>::value>>
|
||||
inline auto mul(T lhs, U rhs) -> uintmax {
|
||||
return lhs * rhs;
|
||||
}
|
||||
|
||||
template<typename T, enable_if_t<is_unsigned<T>::value>>
|
||||
inline auto square(T value) -> uintmax {
|
||||
return value * value;
|
||||
}
|
||||
|
||||
template<typename T, typename U> alwaysinline auto rol(const T& lhs, const U& rhs, enable_if_t<is_unsigned<T>::value>* = 0) -> T {
|
||||
return lhs << rhs | lhs >> (sizeof(T) * 8 - rhs);
|
||||
template<typename T, typename U>
|
||||
inline auto rol(T lhs, U rhs, enable_if_t<is_unsigned<T>::value>* = 0) -> T {
|
||||
return lhs << rhs | lhs >> sizeof(T) * 8 - rhs;
|
||||
}
|
||||
|
||||
template<typename T, typename U> alwaysinline auto ror(const T& lhs, const U& rhs, enable_if_t<is_unsigned<T>::value>* = 0) -> T {
|
||||
return lhs >> rhs | lhs << (sizeof(T) * 8 - rhs);
|
||||
template<typename T, typename U>
|
||||
inline auto ror(T lhs, U rhs, enable_if_t<is_unsigned<T>::value>* = 0) -> T {
|
||||
return lhs >> rhs | lhs << sizeof(T) * 8 - rhs;
|
||||
}
|
||||
|
||||
#if INTMAX_BITS >= 128
|
||||
|
@ -41,6 +41,14 @@ template<typename T> struct array_span : array_view<T> {
|
||||
super::_size--;
|
||||
}
|
||||
|
||||
auto span(uint offset, uint length) const -> type {
|
||||
#ifdef DEBUG
|
||||
struct out_of_bounds {};
|
||||
if(offset + length >= super::_size) throw out_of_bounds{};
|
||||
#endif
|
||||
return {super::_data + offset, length};
|
||||
}
|
||||
|
||||
//array_span<uint8_t> specializations
|
||||
template<typename U> auto writel(U value, uint size) -> void;
|
||||
template<typename U> auto writem(U value, uint size) -> void;
|
||||
|
@ -29,7 +29,7 @@ template<typename T> struct array_view {
|
||||
inline operator const T*() const {
|
||||
#ifdef DEBUG
|
||||
struct out_of_bounds {};
|
||||
if(_size <= 0) throw out_of_bounds{};
|
||||
if(_size < 0) throw out_of_bounds{};
|
||||
#endif
|
||||
return _data;
|
||||
}
|
||||
@ -72,17 +72,29 @@ template<typename T> struct array_view {
|
||||
return value;
|
||||
}
|
||||
|
||||
auto view(uint offset, uint length) const -> type {
|
||||
#ifdef DEBUG
|
||||
struct out_of_bounds {};
|
||||
if(offset + length >= _size) throw out_of_bounds{};
|
||||
#endif
|
||||
return {_data + offset, length};
|
||||
}
|
||||
|
||||
//array_view<uint8_t> specializations
|
||||
template<typename U> auto readl(U& value, uint size) -> U;
|
||||
template<typename U> auto readm(U& value, uint size) -> U;
|
||||
template<typename U> auto readvn(U& value, uint size) -> U;
|
||||
template<typename U> auto readvi(U& value, uint size) -> U;
|
||||
|
||||
template<typename U> auto readl(U& value, uint offset, uint size) -> U { return view(offset, size).readl(value, size); }
|
||||
|
||||
template<typename U = uint64_t> auto readl(uint size) -> U { U value; return readl(value, size); }
|
||||
template<typename U = uint64_t> auto readm(uint size) -> U { U value; return readm(value, size); }
|
||||
template<typename U = uint64_t> auto readvn(uint size) -> U { U value; return readvn(value, size); }
|
||||
template<typename U = int64_t> auto readvi(uint size) -> U { U value; return readvi(value, size); }
|
||||
|
||||
template<typename U = uint64_t> auto readl(uint offset, uint size) -> U { U value; return readl(value, offset, size); }
|
||||
|
||||
protected:
|
||||
const T* _data;
|
||||
int _size;
|
||||
@ -92,13 +104,13 @@ protected:
|
||||
|
||||
template<> template<typename U> inline auto array_view<uint8_t>::readl(U& value, uint size) -> U {
|
||||
value = 0;
|
||||
for(uint byte : range(size)) value |= read() << byte * 8;
|
||||
for(uint byte : range(size)) value |= (U)read() << byte * 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
template<> template<typename U> inline auto array_view<uint8_t>::readm(U& value, uint size) -> U {
|
||||
value = 0;
|
||||
for(uint byte : reverse(range(size))) value |= read() << byte * 8;
|
||||
for(uint byte : reverse(range(size))) value |= (U)read() << byte * 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -1,272 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/cipher/chacha20.hpp>
|
||||
#include <nall/elliptic-curve/ed25519.hpp>
|
||||
#include <nall/encode/base.hpp>
|
||||
#include <nall/decode/base.hpp>
|
||||
#include <nall/encode/lzsa.hpp>
|
||||
#include <nall/decode/lzsa.hpp>
|
||||
|
||||
namespace nall { namespace Beat {
|
||||
|
||||
struct Archive {
|
||||
struct Encryption {
|
||||
string type;
|
||||
uint256_t key = 0;
|
||||
uint192_t nonce = 0;
|
||||
};
|
||||
|
||||
struct Signature {
|
||||
string type;
|
||||
uint256_t privateKey = 0;
|
||||
uint256_t publicKey = 0;
|
||||
uint512_t signature = 0;
|
||||
};
|
||||
|
||||
struct Compression {
|
||||
string type;
|
||||
uint size = 0;
|
||||
};
|
||||
|
||||
//timestamps are human-readable strings in ISO 8601 format; save for T=>space
|
||||
//times are stored in UTC, rather than local times
|
||||
struct Timestamps {
|
||||
string created;
|
||||
string modified;
|
||||
string accessed;
|
||||
};
|
||||
|
||||
struct Permissions {
|
||||
string name;
|
||||
bool readable = false;
|
||||
bool writable = false;
|
||||
bool executable = false;
|
||||
};
|
||||
|
||||
struct Node {
|
||||
string name;
|
||||
|
||||
//paths and files
|
||||
Timestamps timestamps;
|
||||
struct {
|
||||
Permissions owner;
|
||||
Permissions group;
|
||||
Permissions other;
|
||||
} permissions;
|
||||
|
||||
//files only
|
||||
uint offset = 0;
|
||||
uint size = 0;
|
||||
|
||||
Compression compression;
|
||||
|
||||
string filename;
|
||||
vector<uint8_t> filedata;
|
||||
};
|
||||
|
||||
auto append(const Node& node) -> bool;
|
||||
auto encryptionManifest() -> string;
|
||||
auto manifest() -> string;
|
||||
auto create() -> vector<uint8_t>;
|
||||
|
||||
//internal functions
|
||||
auto encode() -> vector<uint8_t>;
|
||||
auto encode(Node& node, uint64_t offset) -> vector<uint8_t>;
|
||||
|
||||
Encryption encryption;
|
||||
Signature signature;
|
||||
Compression compression; //solid archiving
|
||||
vector<Node> nodes;
|
||||
};
|
||||
|
||||
auto Archive::append(const Node& node) -> bool {
|
||||
//prevent multiple nodes with the same name
|
||||
if(nodes.find([&](auto& item) { return item.name == node.name; })) return false;
|
||||
|
||||
nodes.append(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Archive::encryptionManifest() -> string {
|
||||
string manifest;
|
||||
manifest.append("encryption\n");
|
||||
manifest.append(" type: ", encryption.type, "\n");
|
||||
manifest.append(" nonce: ", Encode::Base<57>(encryption.nonce), "\n");
|
||||
return manifest;
|
||||
}
|
||||
|
||||
auto Archive::manifest() -> string {
|
||||
string manifest;
|
||||
manifest.append("archive\n");
|
||||
|
||||
for(auto& node : nodes) {
|
||||
if(node.name.endsWith("/")) {
|
||||
manifest.append(" path: ", string{node.name}.trimRight("/", 1L), "\n");
|
||||
} else {
|
||||
manifest.append(" file: ", node.name, "\n");
|
||||
manifest.append(" offset: ", node.offset, "\n");
|
||||
manifest.append(" size: ", node.size, "\n");
|
||||
if(node.compression.type) {
|
||||
manifest.append(" compression: ", node.compression.type, "\n");
|
||||
manifest.append(" size: ", node.compression.size, "\n");
|
||||
}
|
||||
}
|
||||
if(node.timestamps.created || node.timestamps.modified || node.timestamps.accessed) {
|
||||
manifest.append(" timestamp\n");
|
||||
if(auto timestamp = node.timestamps.created ) manifest.append(" created: ", timestamp, "\n");
|
||||
if(auto timestamp = node.timestamps.modified) manifest.append(" modified: ", timestamp, "\n");
|
||||
if(auto timestamp = node.timestamps.accessed) manifest.append(" accessed: ", timestamp, "\n");
|
||||
}
|
||||
if(node.permissions.owner.name || node.permissions.group.name || node.permissions.other.name) {
|
||||
manifest.append(" permission\n");
|
||||
if(node.permissions.owner.name) {
|
||||
manifest.append(" owner: ", node.permissions.owner.name, "\n");
|
||||
if(node.permissions.owner.readable ) manifest.append(" readable\n");
|
||||
if(node.permissions.owner.writable ) manifest.append(" writable\n");
|
||||
if(node.permissions.owner.executable) manifest.append(" executable\n");
|
||||
}
|
||||
if(node.permissions.group.name) {
|
||||
manifest.append(" group: ", node.permissions.group.name, "\n");
|
||||
if(node.permissions.group.readable ) manifest.append(" readable\n");
|
||||
if(node.permissions.group.writable ) manifest.append(" writable\n");
|
||||
if(node.permissions.group.executable) manifest.append(" executable\n");
|
||||
}
|
||||
if(node.permissions.other.name) {
|
||||
manifest.append(" other\n");
|
||||
if(node.permissions.other.readable ) manifest.append(" readable\n");
|
||||
if(node.permissions.other.writable ) manifest.append(" writable\n");
|
||||
if(node.permissions.other.executable) manifest.append(" executable\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(compression.type) {
|
||||
manifest.append(" compression: ", compression.type, "\n");
|
||||
manifest.append(" size: ", compression.size, "\n");
|
||||
}
|
||||
|
||||
if(signature.type == "ed25519") {
|
||||
manifest.append(" signature: ", signature.type, "\n");
|
||||
manifest.append(" publicKey: ", Encode::Base<57>(signature.publicKey), "\n");
|
||||
manifest.append(" signature: ", Encode::Base<57>(signature.signature), "\n");
|
||||
}
|
||||
|
||||
return manifest;
|
||||
}
|
||||
|
||||
auto Archive::create() -> vector<uint8_t> {
|
||||
vector<uint8_t> output;
|
||||
|
||||
output.append('B');
|
||||
output.append('P');
|
||||
output.append('A');
|
||||
output.append('1');
|
||||
|
||||
nodes.sort([&](auto& lhs, auto& rhs) {
|
||||
return string::compare(lhs.name, rhs.name) < 0;
|
||||
});
|
||||
|
||||
auto content = encode();
|
||||
if(compression.type == "lzsa") {
|
||||
content = Encode::LZSA(content);
|
||||
compression.size = content.size();
|
||||
}
|
||||
|
||||
if(signature.type == "ed25519") {
|
||||
EllipticCurve::Ed25519 ed25519;
|
||||
signature.publicKey = ed25519.publicKey(signature.privateKey);
|
||||
signature.signature = ed25519.sign(content, signature.privateKey);
|
||||
}
|
||||
|
||||
if(encryption.type == "xchacha20") {
|
||||
//a randomly generated nonce is preferred
|
||||
if(!encryption.nonce) {
|
||||
CSPRNG csprng;
|
||||
encryption.nonce = csprng.random<uint192_t>();
|
||||
}
|
||||
Cipher::XChaCha20 xchacha20{encryption.key, encryption.nonce};
|
||||
content = xchacha20.encrypt(content);
|
||||
|
||||
string manifest;
|
||||
manifest.append("encryption\n");
|
||||
manifest.append(" type: ", encryption.type, "\n");
|
||||
manifest.append(" nonce: ", Encode::Base<57>(encryption.nonce), "\n");
|
||||
|
||||
output.append(content);
|
||||
for(uint8_t byte : manifest) output.append(byte);
|
||||
output.appendl(manifest.size(), 8);
|
||||
} else {
|
||||
encryption = {};
|
||||
output.append(content);
|
||||
}
|
||||
|
||||
auto sha256 = Hash::SHA256(output).value();
|
||||
output.appendl(sha256, 32);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto Archive::encode() -> vector<uint8_t> {
|
||||
vector<uint8_t> output;
|
||||
|
||||
for(auto& node : nodes) {
|
||||
if(node.filename) {
|
||||
node.timestamps.created = chrono::utc::datetime(inode::timestamp(node.filename, inode::time::create));
|
||||
node.timestamps.accessed = chrono::utc::datetime(inode::timestamp(node.filename, inode::time::access));
|
||||
node.timestamps.modified = chrono::utc::datetime(inode::timestamp(node.filename, inode::time::modify));
|
||||
|
||||
uint mode = inode::mode(node.filename);
|
||||
node.permissions.owner.name = inode::user(node.filename);
|
||||
node.permissions.owner.executable = mode & 0100;
|
||||
node.permissions.owner.writable = mode & 0200;
|
||||
node.permissions.owner.readable = mode & 0400;
|
||||
node.permissions.group.name = inode::group(node.filename);
|
||||
node.permissions.group.executable = mode & 0010;
|
||||
node.permissions.group.writable = mode & 0020;
|
||||
node.permissions.group.readable = mode & 0040;
|
||||
node.permissions.other.name = " ";
|
||||
node.permissions.other.executable = mode & 0001;
|
||||
node.permissions.other.writable = mode & 0002;
|
||||
node.permissions.other.readable = mode & 0004;
|
||||
}
|
||||
|
||||
if(node.name.endsWith("/")) continue;
|
||||
|
||||
auto buffer = encode(node, output.size());
|
||||
output.append(buffer);
|
||||
}
|
||||
|
||||
auto manifest = this->manifest();
|
||||
for(auto byte : manifest) output.append(byte);
|
||||
for(auto byte : range(8)) output.append((uint64_t)manifest.size() >> byte * 8);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
auto Archive::encode(Node& node, uint64_t offset) -> vector<uint8_t> {
|
||||
node.offset = offset;
|
||||
|
||||
vector<uint8_t> output;
|
||||
|
||||
if(node.filename) {
|
||||
output = file::read(node.filename);
|
||||
} else {
|
||||
output = node.filedata;
|
||||
}
|
||||
|
||||
node.size = output.size();
|
||||
|
||||
if(node.compression.type == "lzsa") {
|
||||
output = Encode::LZSA(output);
|
||||
node.compression.size = output.size();
|
||||
} else {
|
||||
node.compression = {};
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}}
|
200
nall/beat/archive/container.hpp
Normal file
200
nall/beat/archive/container.hpp
Normal file
@ -0,0 +1,200 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/beat/archive/node.hpp>
|
||||
|
||||
namespace nall { namespace Beat { namespace Archive {
|
||||
|
||||
struct Container {
|
||||
Container(array_view<uint8_t> = {});
|
||||
~Container();
|
||||
|
||||
auto isCompressed() const -> bool { return (bool)compression.type; }
|
||||
auto isSigned() const -> bool { return (bool)signature.type; }
|
||||
auto isEncrypted() const -> bool { return (bool)encryption.type; }
|
||||
|
||||
auto compressLZSA() -> void;
|
||||
auto signEd25519(uint256_t privateKey) -> void;
|
||||
auto encryptXChaCha20(uint256_t privateKey, uint192_t nonce = 0) -> void;
|
||||
|
||||
auto validate() -> bool;
|
||||
auto decryptXChaCha20(uint256_t privateKey) -> bool;
|
||||
auto verifyEd25519(uint256_t publicKey) -> bool;
|
||||
auto decompressLZSA() -> bool;
|
||||
|
||||
auto append(string name, string location) -> shared_pointer<Node>;
|
||||
auto appendPath(string name) -> shared_pointer<Node>;
|
||||
auto appendFile(string name, array_view<uint8_t> memory) -> shared_pointer<Node>;
|
||||
auto remove(string name) -> bool;
|
||||
auto find(string name) -> shared_pointer<Node>;
|
||||
auto sort() -> void;
|
||||
|
||||
auto begin() { return nodes.begin(); }
|
||||
auto end() { return nodes.end(); }
|
||||
|
||||
auto begin() const { return nodes.begin(); }
|
||||
auto end() const { return nodes.end(); }
|
||||
|
||||
auto rbegin() { return nodes.rbegin(); }
|
||||
auto rend() { return nodes.rend(); }
|
||||
|
||||
auto rbegin() const { return nodes.rbegin(); }
|
||||
auto rend() const { return nodes.rend(); }
|
||||
|
||||
vector<shared_pointer<Node>> nodes;
|
||||
vector<uint8_t> memory;
|
||||
string metadata;
|
||||
|
||||
struct Compression {
|
||||
string type;
|
||||
} compression;
|
||||
|
||||
struct Signature {
|
||||
string type;
|
||||
uint256_t privateKey = 0;
|
||||
uint256_t publicKey = 0;
|
||||
uint512_t value = 0;
|
||||
} signature;
|
||||
|
||||
struct Encryption {
|
||||
string type;
|
||||
uint256_t privateKey = 0;
|
||||
uint192_t nonce = 0;
|
||||
} encryption;
|
||||
};
|
||||
|
||||
Container::Container(array_view<uint8_t> memory) {
|
||||
this->memory.resize(memory.size());
|
||||
nall::memory::copy(this->memory.data(), memory.data(), memory.size());
|
||||
}
|
||||
|
||||
Container::~Container() {
|
||||
metadata = {};
|
||||
signature = {};
|
||||
encryption = {};
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto Container::compressLZSA() -> void {
|
||||
compression.type = "lzsa";
|
||||
}
|
||||
|
||||
auto Container::signEd25519(uint256_t privateKey) -> void {
|
||||
signature.type = "ed25519";
|
||||
signature.privateKey = privateKey;
|
||||
}
|
||||
|
||||
auto Container::encryptXChaCha20(uint256_t privateKey, uint192_t nonce) -> void {
|
||||
if(!nonce) {
|
||||
CSPRNG::XChaCha20 csprng;
|
||||
nonce = csprng.random<uint192_t>();
|
||||
}
|
||||
|
||||
encryption.type = "xchacha20";
|
||||
encryption.privateKey = privateKey;
|
||||
encryption.nonce = nonce;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto Container::validate() -> bool {
|
||||
array_view<uint8_t> memory = this->memory;
|
||||
if(memory.size() < 44) return false; //8 (metadata size) + 32 (SHA256) + 4 (signature)
|
||||
|
||||
if(memory[memory.size() - 4] != 'B') return false;
|
||||
if(memory[memory.size() - 3] != 'P') return false;
|
||||
if(memory[memory.size() - 2] != 'A') return false;
|
||||
if(memory[memory.size() - 1] != '1') return false;
|
||||
|
||||
auto sha256 = memory.readl<uint256_t>(memory.size() - 36, 32);
|
||||
if(Hash::SHA256({memory.data(), memory.size() - 36}).value() != sha256) return false;
|
||||
|
||||
auto size = memory.readl<uint64_t>(memory.size() - 44, 8);
|
||||
|
||||
if(size & 1ull << 63) {
|
||||
size -= 1ull << 63;
|
||||
metadata = memory.view(memory.size() - 44 - size, size);
|
||||
uint64_t offset = memory.size() - 44 - size;
|
||||
for(auto& byte : metadata) byte ^= offset++;
|
||||
} else {
|
||||
metadata = memory.view(memory.size() - 44 - size, size);
|
||||
}
|
||||
|
||||
auto document = BML::unserialize(metadata);
|
||||
|
||||
if(auto node = document["archive/encryption"]) {
|
||||
if(node.text() == "xchacha20") {
|
||||
encryption.type = node.text();
|
||||
encryption.nonce = Decode::Base<57, uint192_t>(node["nonce"].text());
|
||||
}
|
||||
}
|
||||
|
||||
if(auto node = document["archive/signature"]) {
|
||||
if(node.text() == "ed25519") {
|
||||
signature.type = node.text();
|
||||
signature.publicKey = Decode::Base<57, uint256_t>(node["publicKey"].text());
|
||||
signature.value = Decode::Base<57, uint512_t>(node["value"].text());
|
||||
}
|
||||
}
|
||||
|
||||
if(auto node = document["archive/compression"]) {
|
||||
compression.type = node.text();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Container::decryptXChaCha20(uint256_t privateKey) -> bool {
|
||||
encryption.privateKey = privateKey;
|
||||
Cipher::XChaCha20 xchacha20{encryption.privateKey, encryption.nonce};
|
||||
auto size = memory.readl<uint64_t>(memory.size() - 44, 8);
|
||||
memory = xchacha20.decrypt(memory.view(0, memory.size() - 44 - size));
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Container::verifyEd25519(uint256_t publicKey) -> bool {
|
||||
EllipticCurve::Ed25519 ed25519;
|
||||
auto size = memory.readl<uint64_t>(memory.size() - 44, 8);
|
||||
return ed25519.verify(memory.view(0, memory.size() - 44 - size), signature.value, publicKey);
|
||||
}
|
||||
|
||||
auto Container::decompressLZSA() -> bool {
|
||||
memory = Decode::LZSA(memory);
|
||||
return (bool)memory;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto Container::append(string name, string location) -> shared_pointer<Node> {
|
||||
for(auto& node : nodes) if(node->name == name) return {};
|
||||
if(auto node = Node::create(name, location)) return nodes.append(node), node;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Container::appendPath(string name) -> shared_pointer<Node> {
|
||||
for(auto& node : nodes) if(node->name == name) return {};
|
||||
if(auto node = Node::createPath(name)) return nodes.append(node), node;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Container::appendFile(string name, array_view<uint8_t> memory) -> shared_pointer<Node> {
|
||||
for(auto& node : nodes) if(node->name == name) return {};
|
||||
if(auto node = Node::createFile(name, memory)) return nodes.append(node), node;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Container::remove(string name) -> bool {
|
||||
if(auto offset = nodes.find([&](auto& node) { return node->name == name; })) return nodes.remove(*offset), true;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Container::find(string name) -> shared_pointer<Node> {
|
||||
if(auto offset = nodes.find([&](auto& node) { return node->name == name; })) return nodes[*offset];
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Container::sort() -> void {
|
||||
nodes.sort([&](auto& lhs, auto& rhs) { return string::icompare(lhs->name, rhs->name) < 0; });
|
||||
}
|
||||
|
||||
}}}
|
86
nall/beat/archive/create.hpp
Normal file
86
nall/beat/archive/create.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/beat/archive/node.hpp>
|
||||
#include <nall/beat/archive/container.hpp>
|
||||
|
||||
namespace nall { namespace Beat { namespace Archive {
|
||||
|
||||
auto create(Container& container, string name) -> vector<uint8_t> {
|
||||
auto& metadata = container.metadata;
|
||||
metadata = {};
|
||||
metadata.append("archive: ", Location::file(name), "\n");
|
||||
|
||||
vector<uint8_t> memory;
|
||||
|
||||
container.sort();
|
||||
for(auto& node : container.nodes) {
|
||||
if(node->isFile()) {
|
||||
node->offset = memory.size();
|
||||
memory.append(node->memory);
|
||||
}
|
||||
metadata.append(node->metadata());
|
||||
}
|
||||
|
||||
metadata.append(" size: ", memory.size(), "\n");
|
||||
|
||||
if(container.compression.type == "lzsa") {
|
||||
memory = Encode::LZSA(memory);
|
||||
metadata.append(" compression: lzsa\n");
|
||||
metadata.append(" size: ", memory.size(), "\n");
|
||||
}
|
||||
|
||||
if(container.signature.type == "ed25519") {
|
||||
EllipticCurve::Ed25519 ed25519;
|
||||
container.signature.publicKey = ed25519.publicKey(container.signature.privateKey);
|
||||
container.signature.value = ed25519.sign(memory, container.signature.privateKey);
|
||||
|
||||
metadata.append(" signature: ed25519\n");
|
||||
metadata.append(" publicKey: ", Encode::Base<57>(container.signature.publicKey), "\n");
|
||||
metadata.append(" value: ", Encode::Base<57>(container.signature.value), "\n");
|
||||
}
|
||||
|
||||
for(auto& byte : metadata) memory.append(byte);
|
||||
memory.appendl((uint64_t)metadata.size(), 8);
|
||||
|
||||
auto sha256 = Hash::SHA256(memory).value();
|
||||
memory.appendl((uint256_t)sha256, 32);
|
||||
|
||||
memory.append('B');
|
||||
memory.append('P');
|
||||
memory.append('A');
|
||||
memory.append('1');
|
||||
|
||||
if(container.encryption.type == "xchacha20") {
|
||||
Cipher::XChaCha20 xchacha20{container.encryption.privateKey, container.encryption.nonce};
|
||||
memory = xchacha20.encrypt(memory);
|
||||
|
||||
metadata = {};
|
||||
metadata.append("archive\n");
|
||||
metadata.append(" encryption: xchacha20\n");
|
||||
metadata.append(" nonce: ", Encode::Base<57>(container.encryption.nonce), "\n");
|
||||
|
||||
if(container.signature.type == "ed25519") {
|
||||
EllipticCurve::Ed25519 ed25519;
|
||||
container.signature.value = ed25519.sign(memory, container.signature.privateKey);
|
||||
|
||||
metadata.append(" signature: ed25519\n");
|
||||
//metadata.append(" publicKey: ", Encode::Base<57>(container.signature.publicKey), "\n");
|
||||
metadata.append(" value: ", Encode::Base<57>(container.signature.value), "\n");
|
||||
}
|
||||
|
||||
for(auto& byte : metadata) memory.append(byte ^ memory.size());
|
||||
memory.appendl((uint64_t)metadata.size() | 1ull << 63, 8);
|
||||
|
||||
auto sha256 = Hash::SHA256(memory).value();
|
||||
memory.appendl((uint256_t)sha256, 32);
|
||||
|
||||
memory.append('B');
|
||||
memory.append('P');
|
||||
memory.append('A');
|
||||
memory.append('1');
|
||||
}
|
||||
|
||||
return memory;
|
||||
}
|
||||
|
||||
}}}
|
27
nall/beat/archive/extract.hpp
Normal file
27
nall/beat/archive/extract.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/beat/archive/node.hpp>
|
||||
#include <nall/beat/archive/container.hpp>
|
||||
|
||||
namespace nall { namespace Beat { namespace Archive {
|
||||
|
||||
auto extract(Container& container) -> bool {
|
||||
function<void (Markup::Node)> extract = [&](auto metadata) {
|
||||
if(metadata.name() != "path" && metadata.name() != "file") return;
|
||||
shared_pointer<Node> node = new Node;
|
||||
if(node->unserialize(container.memory, metadata)) {
|
||||
container.nodes.append(node);
|
||||
}
|
||||
if(metadata.name() != "path") return;
|
||||
for(auto node : metadata) extract(node);
|
||||
};
|
||||
|
||||
container.nodes.reset();
|
||||
auto document = BML::unserialize(container.metadata);
|
||||
for(auto node : document["archive"]) extract(node);
|
||||
container.sort();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}}}
|
332
nall/beat/archive/node.hpp
Normal file
332
nall/beat/archive/node.hpp
Normal file
@ -0,0 +1,332 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/arithmetic.hpp>
|
||||
#include <nall/array-view.hpp>
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/cipher/chacha20.hpp>
|
||||
#include <nall/elliptic-curve/ed25519.hpp>
|
||||
#include <nall/decode/base.hpp>
|
||||
#include <nall/encode/base.hpp>
|
||||
#include <nall/decode/lzsa.hpp>
|
||||
#include <nall/encode/lzsa.hpp>
|
||||
|
||||
namespace nall { namespace Beat { namespace Archive {
|
||||
|
||||
struct Node {
|
||||
static auto create(string name, string location) -> shared_pointer<Node>;
|
||||
static auto createPath(string name) -> shared_pointer<Node>;
|
||||
static auto createFile(string name, array_view<uint8_t> memory) -> shared_pointer<Node>;
|
||||
|
||||
explicit operator bool() const { return (bool)name; }
|
||||
auto isPath() const -> bool { return name.endsWith("/"); }
|
||||
auto isFile() const -> bool { return !name.endsWith("/"); }
|
||||
auto isCompressed() const -> bool { return (bool)compression.type; }
|
||||
|
||||
auto metadata(bool indented = true) const -> string;
|
||||
auto compressLZSA() -> bool;
|
||||
|
||||
auto unserialize(array_view<uint8_t> container, Markup::Node metadata) -> bool;
|
||||
auto decompress() -> bool;
|
||||
|
||||
auto getTimestamp(string) const -> uint64_t;
|
||||
auto getPermissions() const -> uint;
|
||||
auto getOwner() const -> string;
|
||||
auto getGroup() const -> string;
|
||||
|
||||
//files and paths
|
||||
string name;
|
||||
|
||||
bool timestamps = false;
|
||||
struct Timestamp {
|
||||
string created;
|
||||
string modified;
|
||||
string accessed;
|
||||
} timestamp;
|
||||
|
||||
bool permissions = false;
|
||||
struct Permission {
|
||||
struct Owner {
|
||||
string name;
|
||||
bool readable = false;
|
||||
bool writable = false;
|
||||
bool executable = false;
|
||||
} owner;
|
||||
struct Group {
|
||||
string name;
|
||||
bool readable = false;
|
||||
bool writable = false;
|
||||
bool executable = false;
|
||||
} group;
|
||||
struct Other {
|
||||
bool readable = false;
|
||||
bool writable = false;
|
||||
bool executable = false;
|
||||
} other;
|
||||
} permission;
|
||||
|
||||
//files only
|
||||
vector<uint8_t> memory;
|
||||
uint64_t offset = 0;
|
||||
|
||||
struct Compression {
|
||||
string type;
|
||||
uint size = 0; //decompressed size; memory.size() == compressed size
|
||||
} compression;
|
||||
};
|
||||
|
||||
auto Node::create(string name, string location) -> shared_pointer<Node> {
|
||||
if(!inode::exists(location)) return {};
|
||||
shared_pointer<Node> node = new Node;
|
||||
|
||||
node->name = name;
|
||||
|
||||
node->timestamps = true;
|
||||
node->timestamp.created = chrono::utc::datetime(inode::timestamp(location, inode::time::create));
|
||||
node->timestamp.modified = chrono::utc::datetime(inode::timestamp(location, inode::time::modify));
|
||||
node->timestamp.accessed = chrono::utc::datetime(inode::timestamp(location, inode::time::access));
|
||||
|
||||
uint mode = inode::mode(location);
|
||||
node->permissions = true;
|
||||
node->permission.owner.name = inode::owner(location);
|
||||
node->permission.group.name = inode::group(location);
|
||||
node->permission.owner.readable = mode & 0400;
|
||||
node->permission.owner.writable = mode & 0200;
|
||||
node->permission.owner.executable = mode & 0100;
|
||||
node->permission.group.readable = mode & 0040;
|
||||
node->permission.group.writable = mode & 0020;
|
||||
node->permission.group.executable = mode & 0010;
|
||||
node->permission.other.readable = mode & 0004;
|
||||
node->permission.other.writable = mode & 0002;
|
||||
node->permission.other.executable = mode & 0001;
|
||||
|
||||
if(file::exists(location)) {
|
||||
node->memory = file::read(location);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
auto Node::createPath(string name) -> shared_pointer<Node> {
|
||||
if(!name) return {};
|
||||
shared_pointer<Node> node = new Node;
|
||||
node->name = name;
|
||||
return node;
|
||||
}
|
||||
|
||||
auto Node::createFile(string name, array_view<uint8_t> memory) -> shared_pointer<Node> {
|
||||
if(!name) return {};
|
||||
shared_pointer<Node> node = new Node;
|
||||
node->name = name;
|
||||
node->memory.resize(memory.size());
|
||||
memory::copy(node->memory.data(), memory.data(), memory.size());
|
||||
return node;
|
||||
}
|
||||
|
||||
auto Node::metadata(bool indented) const -> string {
|
||||
string metadata;
|
||||
if(!name) return metadata;
|
||||
|
||||
string indent;
|
||||
if(indented) {
|
||||
indent.append(" ");
|
||||
auto bytes = string{name}.trimRight("/");
|
||||
for(auto& byte : bytes) {
|
||||
if(byte == '/') indent.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
if(isPath()) {
|
||||
metadata.append(indent, "path: ", name, "\n");
|
||||
}
|
||||
|
||||
if(isFile()) {
|
||||
metadata.append(indent, "file: ", name, "\n");
|
||||
}
|
||||
|
||||
if(timestamps) {
|
||||
metadata.append(indent, " timestamp\n");
|
||||
if(timestamp.created != timestamp.modified)
|
||||
metadata.append(indent, " created: ", timestamp.created, "\n");
|
||||
metadata.append(indent, " modified: ", timestamp.modified, "\n");
|
||||
if(timestamp.accessed != timestamp.modified)
|
||||
metadata.append(indent, " accessed: ", timestamp.accessed, "\n");
|
||||
}
|
||||
|
||||
if(permissions) {
|
||||
metadata.append(indent, " permission\n");
|
||||
metadata.append(indent, " owner: ", permission.owner.name, "\n");
|
||||
if(permission.owner.readable)
|
||||
metadata.append(indent, " readable\n");
|
||||
if(permission.owner.writable)
|
||||
metadata.append(indent, " writable\n");
|
||||
if(permission.owner.executable)
|
||||
metadata.append(indent, " executable\n");
|
||||
metadata.append(indent, " group: ", permission.group.name, "\n");
|
||||
if(permission.group.readable)
|
||||
metadata.append(indent, " readable\n");
|
||||
if(permission.group.writable)
|
||||
metadata.append(indent, " writable\n");
|
||||
if(permission.group.executable)
|
||||
metadata.append(indent, " executable\n");
|
||||
metadata.append(indent, " other\n");
|
||||
if(permission.other.readable)
|
||||
metadata.append(indent, " readable\n");
|
||||
if(permission.other.writable)
|
||||
metadata.append(indent, " writable\n");
|
||||
if(permission.other.executable)
|
||||
metadata.append(indent, " executable\n");
|
||||
}
|
||||
|
||||
if(isFile()) {
|
||||
metadata.append(indent, " offset: ", offset, "\n");
|
||||
if(!isCompressed()) {
|
||||
metadata.append(indent, " size: ", memory.size(), "\n");
|
||||
} else {
|
||||
metadata.append(indent, " size: ", compression.size, "\n");
|
||||
metadata.append(indent, " compression: ", compression.type, "\n");
|
||||
metadata.append(indent, " size: ", memory.size(), "\n");
|
||||
}
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
auto Node::unserialize(array_view<uint8_t> container, Markup::Node metadata) -> bool {
|
||||
*this = {};
|
||||
if(!metadata.text()) return false;
|
||||
|
||||
name = metadata.text();
|
||||
|
||||
if(auto node = metadata["timestamp"]) {
|
||||
timestamps = true;
|
||||
if(auto created = node["created" ]) timestamp.created = created.text();
|
||||
if(auto modified = node["modified"]) timestamp.modified = modified.text();
|
||||
if(auto accessed = node["accessed"]) timestamp.accessed = accessed.text();
|
||||
}
|
||||
|
||||
if(auto node = metadata["permission"]) {
|
||||
permissions = true;
|
||||
if(auto owner = node["owner"]) {
|
||||
permission.owner.name = owner.text();
|
||||
permission.owner.readable = (bool)owner["readable"];
|
||||
permission.owner.writable = (bool)owner["writable"];
|
||||
permission.owner.executable = (bool)owner["executable"];
|
||||
}
|
||||
if(auto group = node["group"]) {
|
||||
permission.group.name = group.text();
|
||||
permission.group.readable = (bool)group["readable"];
|
||||
permission.group.writable = (bool)group["writable"];
|
||||
permission.group.executable = (bool)group["executable"];
|
||||
}
|
||||
if(auto other = node["other"]) {
|
||||
permission.other.readable = (bool)other["readable"];
|
||||
permission.other.writable = (bool)other["writable"];
|
||||
permission.other.executable = (bool)other["executable"];
|
||||
}
|
||||
}
|
||||
|
||||
if(isPath()) return true;
|
||||
|
||||
uint offset = metadata["offset"].natural();
|
||||
uint size = metadata["size"].natural();
|
||||
|
||||
if(metadata["compression"]) {
|
||||
size = metadata["compression/size"].natural();
|
||||
compression.type = metadata["compression"].text();
|
||||
}
|
||||
|
||||
if(offset + size >= container.size()) return false;
|
||||
|
||||
memory.reallocate(size);
|
||||
nall::memory::copy(memory.data(), container.view(offset, size), size);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Node::compressLZSA() -> bool {
|
||||
if(!memory) return true; //don't compress empty files
|
||||
if(isCompressed()) return true; //don't recompress files
|
||||
|
||||
auto compressedMemory = Encode::LZSA(memory);
|
||||
if(compressedMemory.size() >= memory.size()) return true; //can't compress smaller than original size
|
||||
|
||||
compression.type = "lzsa";
|
||||
compression.size = memory.size();
|
||||
memory = move(compressedMemory);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Node::decompress() -> bool {
|
||||
if(!isCompressed()) return true;
|
||||
|
||||
if(compression.type == "lzsa") {
|
||||
compression = {};
|
||||
memory = Decode::LZSA(memory);
|
||||
return (bool)memory;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Node::getTimestamp(string type) const -> uint64_t {
|
||||
if(!timestamps) return time(nullptr);
|
||||
|
||||
string value = chrono::utc::datetime();
|
||||
if(type == "created" ) value = timestamp.created;
|
||||
if(type == "modified") value = timestamp.modified;
|
||||
if(type == "accessed") value = timestamp.accessed;
|
||||
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
struct tm timeInfo{};
|
||||
if(strptime(value, "%Y-%m-%d %H:%M:%S", &timeInfo) != nullptr) {
|
||||
//todo: not thread safe ...
|
||||
auto tz = getenv("TZ");
|
||||
setenv("TZ", "", 1);
|
||||
timeInfo.tm_isdst = -1;
|
||||
auto result = mktime(&timeInfo);
|
||||
if(tz) setenv("TZ", tz, 1);
|
||||
else unsetenv("TZ");
|
||||
if(result != -1) return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
return time(nullptr);
|
||||
}
|
||||
|
||||
auto Node::getPermissions() const -> uint {
|
||||
if(!permissions) return 0755;
|
||||
uint mode = 0;
|
||||
if(permission.owner.readable ) mode |= 0400;
|
||||
if(permission.owner.writable ) mode |= 0200;
|
||||
if(permission.owner.executable) mode |= 0100;
|
||||
if(permission.group.readable ) mode |= 0040;
|
||||
if(permission.group.writable ) mode |= 0020;
|
||||
if(permission.group.executable) mode |= 0010;
|
||||
if(permission.other.readable ) mode |= 0004;
|
||||
if(permission.other.writable ) mode |= 0002;
|
||||
if(permission.other.executable) mode |= 0001;
|
||||
return mode;
|
||||
}
|
||||
|
||||
auto Node::getOwner() const -> string {
|
||||
if(!permissions || !permission.owner.name) {
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
assert(pwd);
|
||||
return pwd->pw_name;
|
||||
#endif
|
||||
}
|
||||
return permission.owner.name;
|
||||
}
|
||||
|
||||
auto Node::getGroup() const -> string {
|
||||
if(!permissions || !permission.group.name) {
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
struct group* grp = getgrgid(getgid());
|
||||
assert(grp);
|
||||
return grp->gr_name;
|
||||
#endif
|
||||
}
|
||||
return permission.group.name;
|
||||
}
|
||||
|
||||
}}}
|
@ -4,10 +4,8 @@
|
||||
|
||||
namespace nall { namespace Decode {
|
||||
|
||||
inline auto LZSA(const void* data) -> vector<uint8_t> {
|
||||
inline auto LZSA(array_view<uint8_t> input) -> vector<uint8_t> {
|
||||
vector<uint8_t> output;
|
||||
|
||||
auto input = (const uint8_t*)data;
|
||||
uint index = 0;
|
||||
|
||||
uint size = 0;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/file-map.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/decode/inflate.hpp>
|
||||
@ -24,7 +24,7 @@ struct ZIP {
|
||||
|
||||
auto open(const string& filename) -> bool {
|
||||
close();
|
||||
if(fm.open(filename, filemap::mode::read) == false) return false;
|
||||
if(fm.open(filename, file::mode::read) == false) return false;
|
||||
if(open(fm.data(), fm.size()) == false) {
|
||||
fm.close();
|
||||
return false;
|
||||
@ -115,11 +115,11 @@ struct ZIP {
|
||||
}
|
||||
|
||||
auto close() -> void {
|
||||
if(fm.open()) fm.close();
|
||||
if(fm) fm.close();
|
||||
}
|
||||
|
||||
protected:
|
||||
filemap fm;
|
||||
file_map fm;
|
||||
const uint8_t* filedata;
|
||||
uint filesize;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/inode.hpp>
|
||||
#include <nall/intrinsics.hpp>
|
||||
#include <nall/merge-sort.hpp>
|
||||
@ -18,6 +19,8 @@
|
||||
namespace nall {
|
||||
|
||||
struct directory : inode {
|
||||
directory() = delete;
|
||||
|
||||
static auto create(const string& pathname, uint permissions = 0755) -> bool; //recursive
|
||||
static auto remove(const string& pathname) -> bool; //recursive
|
||||
static auto exists(const string& pathname) -> bool;
|
||||
@ -64,6 +67,84 @@ struct directory : inode {
|
||||
return folders;
|
||||
}
|
||||
|
||||
static auto rcontents(const string& pathname, const string& pattern = "*") -> vector<string> {
|
||||
vector<string> contents;
|
||||
function<void (const string&, const string&, const string&)>
|
||||
recurse = [&](const string& basename, const string& pathname, const string& pattern) {
|
||||
for(auto& folder : directory::ufolders(pathname)) {
|
||||
contents.append(string{pathname, folder}.trimLeft(basename, 1L));
|
||||
recurse(basename, {pathname, folder}, pattern);
|
||||
}
|
||||
for(auto& file : directory::ufiles(pathname, pattern)) {
|
||||
contents.append(string{pathname, file}.trimLeft(basename, 1L));
|
||||
}
|
||||
};
|
||||
for(auto& folder : directory::ufolders(pathname)) {
|
||||
contents.append(folder);
|
||||
recurse(pathname, {pathname, folder}, pattern);
|
||||
}
|
||||
for(auto& file : directory::ufiles(pathname, pattern)) {
|
||||
contents.append(file);
|
||||
}
|
||||
contents.sort();
|
||||
return contents;
|
||||
}
|
||||
|
||||
static auto ircontents(const string& pathname, const string& pattern = "*") -> vector<string> {
|
||||
vector<string> contents;
|
||||
function<void (const string&, const string&, const string&)>
|
||||
recurse = [&](const string& basename, const string& pathname, const string& pattern) {
|
||||
for(auto& folder : directory::ufolders(pathname)) {
|
||||
contents.append(string{pathname, folder}.trimLeft(basename, 1L));
|
||||
recurse(basename, {pathname, folder}, pattern);
|
||||
}
|
||||
for(auto& file : directory::ufiles(pathname, pattern)) {
|
||||
contents.append(string{pathname, file}.trimLeft(basename, 1L));
|
||||
}
|
||||
};
|
||||
for(auto& folder : directory::ufolders(pathname)) {
|
||||
contents.append(folder);
|
||||
recurse(pathname, {pathname, folder}, pattern);
|
||||
}
|
||||
for(auto& file : directory::ufiles(pathname, pattern)) {
|
||||
contents.append(file);
|
||||
}
|
||||
contents.isort();
|
||||
return contents;
|
||||
}
|
||||
|
||||
static auto rfolders(const string& pathname, const string& pattern = "*") -> vector<string> {
|
||||
vector<string> folders;
|
||||
for(auto& folder : rcontents(pathname, pattern)) {
|
||||
if(directory::exists({pathname, folder})) folders.append(folder);
|
||||
}
|
||||
return folders;
|
||||
}
|
||||
|
||||
static auto irfolders(const string& pathname, const string& pattern = "*") -> vector<string> {
|
||||
vector<string> folders;
|
||||
for(auto& folder : ircontents(pathname, pattern)) {
|
||||
if(directory::exists({pathname, folder})) folders.append(folder);
|
||||
}
|
||||
return folders;
|
||||
}
|
||||
|
||||
static auto rfiles(const string& pathname, const string& pattern = "*") -> vector<string> {
|
||||
vector<string> files;
|
||||
for(auto& file : rcontents(pathname, pattern)) {
|
||||
if(file::exists({pathname, file})) files.append(file);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
static auto irfiles(const string& pathname, const string& pattern = "*") -> vector<string> {
|
||||
vector<string> files;
|
||||
for(auto& file : ircontents(pathname, pattern)) {
|
||||
if(file::exists({pathname, file})) files.append(file);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
private:
|
||||
//internal functions; these return unsorted lists
|
||||
static auto ufolders(const string& pathname, const string& pattern = "*") -> vector<string>;
|
||||
|
@ -3,50 +3,52 @@
|
||||
#if defined(EC_REFERENCE)
|
||||
#include <nall/elliptic-curve/modulo25519-reference.hpp>
|
||||
#else
|
||||
#include <nall/elliptic-curve/modulo25519.hpp>
|
||||
#include <nall/elliptic-curve/modulo25519-optimized.hpp>
|
||||
#endif
|
||||
|
||||
namespace nall { namespace EllipticCurve {
|
||||
|
||||
struct Curve25519 {
|
||||
auto sharedKey(uint256_t secretKey, uint256_t basepoint = 9) const -> uint256_t {
|
||||
secretKey &= ((0_u256 - 1) >> 2) - 7;
|
||||
secretKey |= 1_u256 << 254;
|
||||
basepoint &= (0_u256 - 1) >> 1;
|
||||
secretKey &= (1_u256 << 254) - 8;
|
||||
secretKey |= (1_u256 << 254);
|
||||
basepoint &= ~0_u256 >> 1;
|
||||
|
||||
point p = scalarMultiply(secretKey, modP(basepoint));
|
||||
return p.x * p.z.reciprocal();
|
||||
point p = scalarMultiply(basepoint % P, secretKey);
|
||||
field k = p.x * reciprocal(p.z);
|
||||
return k();
|
||||
}
|
||||
|
||||
private:
|
||||
using field = Modulo25519;
|
||||
struct point { field x, z; };
|
||||
|
||||
inline auto montgomeryAdd(point p, point q, field b) const -> point {
|
||||
return {
|
||||
(p.x * q.x - p.z * q.z).square(),
|
||||
(p.x * q.z - p.z * q.x).square() * b
|
||||
};
|
||||
}
|
||||
const BarrettReduction<256> P = BarrettReduction<256>{EllipticCurve::P};
|
||||
|
||||
inline auto montgomeryDouble(point p) const -> point {
|
||||
field a = (p.x + p.z).square();
|
||||
field b = (p.x - p.z).square();
|
||||
field a = square(p.x + p.z);
|
||||
field b = square(p.x - p.z);
|
||||
field c = a - b;
|
||||
field d = a + c * 121665;
|
||||
return {a * b, c * d};
|
||||
}
|
||||
|
||||
inline auto scalarMultiply(uint256_t e, field b) const -> point {
|
||||
inline auto montgomeryAdd(point p, point q, field b) const -> point {
|
||||
return {
|
||||
square(p.x * q.x - p.z * q.z),
|
||||
square(p.x * q.z - p.z * q.x) * b
|
||||
};
|
||||
}
|
||||
|
||||
inline auto scalarMultiply(field b, uint256_t exponent) const -> point {
|
||||
point p{1, 0}, q{b, 1};
|
||||
for(uint n : reverse(range(255))) {
|
||||
bool bit = e >> n & 1;
|
||||
cswap(bit, p.x, q.x);
|
||||
cswap(bit, p.z, q.z);
|
||||
for(uint bit : reverse(range(255))) {
|
||||
bool condition = exponent >> bit & 1;
|
||||
cswap(condition, p.x, q.x);
|
||||
cswap(condition, p.z, q.z);
|
||||
q = montgomeryAdd(p, q, b);
|
||||
p = montgomeryDouble(p);
|
||||
cswap(bit, p.x, q.x);
|
||||
cswap(bit, p.z, q.z);
|
||||
cswap(condition, p.x, q.x);
|
||||
cswap(condition, p.z, q.z);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
@ -4,64 +4,42 @@
|
||||
#if defined(EC_REFERENCE)
|
||||
#include <nall/elliptic-curve/modulo25519-reference.hpp>
|
||||
#else
|
||||
#include <nall/elliptic-curve/modulo25519.hpp>
|
||||
#include <nall/elliptic-curve/modulo25519-optimized.hpp>
|
||||
#endif
|
||||
|
||||
namespace nall { namespace EllipticCurve {
|
||||
|
||||
static const uint256_t L = (1_u256 << 252) + 27742317777372353535851937790883648493_u256;
|
||||
|
||||
struct Ed25519 {
|
||||
Ed25519() {
|
||||
field y = field(4) * field(5).reciprocal();
|
||||
field x = recoverX(y);
|
||||
point B{x, y, 1, x * y};
|
||||
for(uint n : range(253)) {
|
||||
Bscalar[n] = B;
|
||||
B = edwardsDouble(B);
|
||||
}
|
||||
}
|
||||
|
||||
auto publicKey(uint256_t privateKey) const -> uint256_t {
|
||||
auto H = uint512_t{Hash::SHA512(to_vector(privateKey)).output()};
|
||||
auto a = clamp(H);
|
||||
auto A = compress(scalarMultiplyB(modL(a)));
|
||||
return A;
|
||||
return compress(scalarMultiply(B, clamp(hash(privateKey)) % L));
|
||||
}
|
||||
|
||||
auto sign(const vector<uint8_t>& message, uint256_t privateKey) const -> uint512_t {
|
||||
auto H = uint512_t{Hash::SHA512(to_vector(privateKey)).output()};
|
||||
auto a = clamp(H);
|
||||
auto A = compress(scalarMultiplyB(modL(a)));
|
||||
auto sign(array_view<uint8_t> message, uint256_t privateKey) const -> uint512_t {
|
||||
uint512_t H = hash(privateKey);
|
||||
uint256_t a = clamp(H) % L;
|
||||
uint256_t A = compress(scalarMultiply(B, a));
|
||||
|
||||
Hash::SHA512 hash1;
|
||||
hash1.input(to_vector(upper(H)));
|
||||
hash1.input(message);
|
||||
auto r = uint512_t{hash1.output()};
|
||||
auto R = compress(scalarMultiplyB(modL(r)));
|
||||
uint512_t r = hash(upper(H), message) % L;
|
||||
uint256_t R = compress(scalarMultiply(B, r));
|
||||
|
||||
Hash::SHA512 hash2;
|
||||
hash2.input(to_vector(R));
|
||||
hash2.input(to_vector(A));
|
||||
hash2.input(message);
|
||||
uint512_t k = modL(uint512_t{hash2.output()});
|
||||
uint256_t S = modL(k * a + r);
|
||||
uint512_t k = hash(R, A, message) % L;
|
||||
uint256_t S = (k * a + r) % L;
|
||||
|
||||
return uint512_t(S) << 256 | R;
|
||||
}
|
||||
|
||||
auto verify(const vector<uint8_t>& message, uint512_t signature, uint256_t publicKey) const -> bool {
|
||||
auto verify(array_view<uint8_t> message, uint512_t signature, uint256_t publicKey) const -> bool {
|
||||
auto R = decompress(lower(signature));
|
||||
auto A = decompress(publicKey);
|
||||
if(!R || !A) return false;
|
||||
uint256_t S = upper(signature);
|
||||
|
||||
Hash::SHA512 hash;
|
||||
hash.input(to_vector(lower(signature)));
|
||||
hash.input(to_vector(publicKey));
|
||||
hash.input(message);
|
||||
auto r = uint512_t{hash.output()};
|
||||
uint256_t S = upper(signature) % L;
|
||||
uint512_t r = hash(lower(signature), publicKey, message) % L;
|
||||
|
||||
auto p = scalarMultiplyB(modL(S));
|
||||
auto q = edwardsAdd(R(), scalarMultiply(modL(r), A()));
|
||||
auto p = scalarMultiply(B, S);
|
||||
auto q = edwardsAdd(R(), scalarMultiply(A(), r));
|
||||
if(!onCurve(p) || !onCurve(q)) return false;
|
||||
if(p.x * q.z - q.x * p.z) return false;
|
||||
if(p.y * q.z - q.y * p.z) return false;
|
||||
@ -71,31 +49,46 @@ struct Ed25519 {
|
||||
private:
|
||||
using field = Modulo25519;
|
||||
struct point { field x, y, z, t; };
|
||||
point Bscalar[253];
|
||||
const field D = -field(121665) * field(121666).reciprocal();
|
||||
const field D = -field(121665) * reciprocal(field(121666));
|
||||
const point B = *decompress((field(4) * reciprocal(field(5)))());
|
||||
const BarrettReduction<256> L = BarrettReduction<256>{EllipticCurve::L};
|
||||
|
||||
inline auto clamp(uint256_t p) const -> uint256_t {
|
||||
p &= ((0_u256 - 1) >> 2) - 7;
|
||||
p |= 1_u256 << 254;
|
||||
return p;
|
||||
inline auto input(Hash::SHA512&) const -> void {}
|
||||
|
||||
template<typename... P> inline auto input(Hash::SHA512& hash, uint256_t value, P&&... p) const -> void {
|
||||
for(uint byte : range(32)) hash.input(uint8_t(value >> byte * 8));
|
||||
input(hash, forward<P>(p)...);
|
||||
}
|
||||
|
||||
inline auto recoverX(field y) const -> field {
|
||||
field y2 = y.square();
|
||||
field x = ((y2 - 1) * (D * y2 + 1).reciprocal()).squareRoot();
|
||||
return x() & 1 ? -x : x;
|
||||
template<typename... P> inline auto input(Hash::SHA512& hash, array_view<uint8_t> value, P&&... p) const -> void {
|
||||
hash.input(value);
|
||||
input(hash, forward<P>(p)...);
|
||||
}
|
||||
|
||||
template<typename... P> inline auto hash(P&&... p) const -> uint512_t {
|
||||
Hash::SHA512 hash;
|
||||
input(hash, forward<P>(p)...);
|
||||
uint512_t result;
|
||||
for(auto byte : reverse(hash.output())) result = result << 8 | byte;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline auto clamp(uint256_t p) const -> uint256_t {
|
||||
p &= (1_u256 << 254) - 8;
|
||||
p |= (1_u256 << 254);
|
||||
return p;
|
||||
}
|
||||
|
||||
inline auto onCurve(point p) const -> bool {
|
||||
if(!p.z) return false;
|
||||
if(p.x * p.y != p.z * p.t) return false;
|
||||
if(p.y.square() - p.x.square() - p.z.square() - p.t.square() * D) return false;
|
||||
if(p.x * p.y - p.z * p.t) return false;
|
||||
if(square(p.y) - square(p.x) - square(p.z) - square(p.t) * D) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline auto decompress(uint256_t c) const -> maybe<point> {
|
||||
field y = c & (1_u256 << 255) - 1;
|
||||
field x = recoverX(y);
|
||||
field y = c & ~0_u256 >> 1;
|
||||
field x = squareRoot((square(y) - 1) * reciprocal(D * square(y) + 1));
|
||||
if(c >> 255) x = -x;
|
||||
point p{x, y, 1, x * y};
|
||||
if(!onCurve(p)) return nothing;
|
||||
@ -103,18 +96,18 @@ private:
|
||||
}
|
||||
|
||||
inline auto compress(point p) const -> uint256_t {
|
||||
field r = p.z.reciprocal();
|
||||
field r = reciprocal(p.z);
|
||||
field x = p.x * r;
|
||||
field y = p.y * r;
|
||||
return (x() & 1) << 255 | (y() & ((0_u256 - 1) >> 1));
|
||||
return (x & 1) << 255 | (y & ~0_u256 >> 1);
|
||||
}
|
||||
|
||||
inline auto edwardsDouble(point p) const -> point {
|
||||
field a = p.x.square();
|
||||
field b = p.y.square();
|
||||
field c = p.z.square();
|
||||
field a = square(p.x);
|
||||
field b = square(p.y);
|
||||
field c = square(p.z);
|
||||
field d = -a;
|
||||
field e = (p.x + p.y).square() - a - b;
|
||||
field e = square(p.x + p.y) - a - b;
|
||||
field g = d + b;
|
||||
field f = g - (c + c);
|
||||
field h = d - b;
|
||||
@ -133,29 +126,16 @@ private:
|
||||
return {e * f, g * h, f * g, e * h};
|
||||
}
|
||||
|
||||
inline auto scalarMultiply(uint512_t e, point q) const -> point {
|
||||
inline auto scalarMultiply(point q, uint256_t exponent) const -> point {
|
||||
point p{0, 1, 1, 0}, c;
|
||||
for(uint n : reverse(range(253))) {
|
||||
for(uint bit : reverse(range(253))) {
|
||||
p = edwardsDouble(p);
|
||||
c = edwardsAdd(p, q);
|
||||
bool bit = e >> n & 1;
|
||||
cmove(bit, p.x, c.x);
|
||||
cmove(bit, p.y, c.y);
|
||||
cmove(bit, p.z, c.z);
|
||||
cmove(bit, p.t, c.t);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
inline auto scalarMultiplyB(uint512_t e) const -> point {
|
||||
point p{0, 1, 1, 0}, c;
|
||||
for(uint n : reverse(range(253))) {
|
||||
bool bit = e >> n & 1;
|
||||
c = edwardsAdd(p, Bscalar[n]);
|
||||
cmove(bit, p.x, c.x);
|
||||
cmove(bit, p.y, c.y);
|
||||
cmove(bit, p.z, c.z);
|
||||
cmove(bit, p.t, c.t);
|
||||
bool condition = exponent >> bit & 1;
|
||||
cmove(condition, p.x, c.x);
|
||||
cmove(condition, p.y, c.y);
|
||||
cmove(condition, p.z, c.z);
|
||||
cmove(condition, p.t, c.t);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
218
nall/elliptic-curve/modulo25519-optimized.hpp
Normal file
218
nall/elliptic-curve/modulo25519-optimized.hpp
Normal file
@ -0,0 +1,218 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/arithmetic/barrett.hpp>
|
||||
|
||||
namespace nall { namespace EllipticCurve {
|
||||
|
||||
static const uint256_t P = (1_u256 << 255) - 19;
|
||||
|
||||
#define Mask ((1ull << 51) - 1)
|
||||
|
||||
struct Modulo25519 {
|
||||
inline Modulo25519() = default;
|
||||
inline Modulo25519(const Modulo25519&) = default;
|
||||
inline Modulo25519(uint64_t a, uint64_t b = 0, uint64_t c = 0, uint64_t d = 0, uint64_t e = 0) : l{a, b, c, d, e} {}
|
||||
inline Modulo25519(uint256_t n);
|
||||
|
||||
inline explicit operator bool() const { return (bool)operator()(); }
|
||||
inline auto operator[](uint index) -> uint64_t& { return l[index]; }
|
||||
inline auto operator[](uint index) const -> uint64_t { return l[index]; }
|
||||
inline auto operator()() const -> uint256_t;
|
||||
|
||||
private:
|
||||
uint64_t l[5]; //51-bits per limb; 255-bits total
|
||||
};
|
||||
|
||||
inline Modulo25519::Modulo25519(uint256_t n) {
|
||||
l[0] = n >> 0 & Mask;
|
||||
l[1] = n >> 51 & Mask;
|
||||
l[2] = n >> 102 & Mask;
|
||||
l[3] = n >> 153 & Mask;
|
||||
l[4] = n >> 204 & Mask;
|
||||
}
|
||||
|
||||
inline auto Modulo25519::operator()() const -> uint256_t {
|
||||
Modulo25519 o = *this;
|
||||
|
||||
o[1] += (o[0] >> 51); o[0] &= Mask;
|
||||
o[2] += (o[1] >> 51); o[1] &= Mask;
|
||||
o[3] += (o[2] >> 51); o[2] &= Mask;
|
||||
o[4] += (o[3] >> 51); o[3] &= Mask;
|
||||
o[0] += 19 * (o[4] >> 51); o[4] &= Mask;
|
||||
|
||||
o[1] += (o[0] >> 51); o[0] &= Mask;
|
||||
o[2] += (o[1] >> 51); o[1] &= Mask;
|
||||
o[3] += (o[2] >> 51); o[2] &= Mask;
|
||||
o[4] += (o[3] >> 51); o[3] &= Mask;
|
||||
o[0] += 19 * (o[4] >> 51); o[4] &= Mask;
|
||||
|
||||
o[0] += 19;
|
||||
o[1] += (o[0] >> 51); o[0] &= Mask;
|
||||
o[2] += (o[1] >> 51); o[1] &= Mask;
|
||||
o[3] += (o[2] >> 51); o[2] &= Mask;
|
||||
o[4] += (o[3] >> 51); o[3] &= Mask;
|
||||
o[0] += 19 * (o[4] >> 51); o[4] &= Mask;
|
||||
|
||||
o[0] += Mask - 18;
|
||||
o[1] += Mask;
|
||||
o[2] += Mask;
|
||||
o[3] += Mask;
|
||||
o[4] += Mask;
|
||||
|
||||
o[1] += o[0] >> 51; o[0] &= Mask;
|
||||
o[2] += o[1] >> 51; o[1] &= Mask;
|
||||
o[3] += o[2] >> 51; o[2] &= Mask;
|
||||
o[4] += o[3] >> 51; o[3] &= Mask;
|
||||
o[4] &= Mask;
|
||||
|
||||
return (uint256_t)o[0] << 0 | (uint256_t)o[1] << 51 | (uint256_t)o[2] << 102 | (uint256_t)o[3] << 153 | (uint256_t)o[4] << 204;
|
||||
}
|
||||
|
||||
inline auto cmove(bool move, Modulo25519& l, const Modulo25519& r) -> void {
|
||||
uint64_t mask = -move;
|
||||
l[0] ^= mask & (l[0] ^ r[0]);
|
||||
l[1] ^= mask & (l[1] ^ r[1]);
|
||||
l[2] ^= mask & (l[2] ^ r[2]);
|
||||
l[3] ^= mask & (l[3] ^ r[3]);
|
||||
l[4] ^= mask & (l[4] ^ r[4]);
|
||||
}
|
||||
|
||||
inline auto cswap(bool swap, Modulo25519& l, Modulo25519& r) -> void {
|
||||
uint64_t mask = -swap, x;
|
||||
x = mask & (l[0] ^ r[0]); l[0] ^= x; r[0] ^= x;
|
||||
x = mask & (l[1] ^ r[1]); l[1] ^= x; r[1] ^= x;
|
||||
x = mask & (l[2] ^ r[2]); l[2] ^= x; r[2] ^= x;
|
||||
x = mask & (l[3] ^ r[3]); l[3] ^= x; r[3] ^= x;
|
||||
x = mask & (l[4] ^ r[4]); l[4] ^= x; r[4] ^= x;
|
||||
}
|
||||
|
||||
inline auto operator-(const Modulo25519& l) -> Modulo25519 { //P - l
|
||||
Modulo25519 o;
|
||||
uint64_t c;
|
||||
o[0] = 0xfffffffffffda - l[0]; c = o[0] >> 51; o[0] &= Mask;
|
||||
o[1] = 0xffffffffffffe - l[1] + c; c = o[1] >> 51; o[1] &= Mask;
|
||||
o[2] = 0xffffffffffffe - l[2] + c; c = o[2] >> 51; o[2] &= Mask;
|
||||
o[3] = 0xffffffffffffe - l[3] + c; c = o[3] >> 51; o[3] &= Mask;
|
||||
o[4] = 0xffffffffffffe - l[4] + c; c = o[4] >> 51; o[4] &= Mask;
|
||||
o[0] += c * 19;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline auto operator+(const Modulo25519& l, const Modulo25519& r) -> Modulo25519 {
|
||||
Modulo25519 o;
|
||||
uint64_t c;
|
||||
o[0] = l[0] + r[0]; c = o[0] >> 51; o[0] &= Mask;
|
||||
o[1] = l[1] + r[1] + c; c = o[1] >> 51; o[1] &= Mask;
|
||||
o[2] = l[2] + r[2] + c; c = o[2] >> 51; o[2] &= Mask;
|
||||
o[3] = l[3] + r[3] + c; c = o[3] >> 51; o[3] &= Mask;
|
||||
o[4] = l[4] + r[4] + c; c = o[4] >> 51; o[4] &= Mask;
|
||||
o[0] += c * 19;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline auto operator-(const Modulo25519& l, const Modulo25519& r) -> Modulo25519 {
|
||||
Modulo25519 o;
|
||||
uint64_t c;
|
||||
o[0] = l[0] + 0x1fffffffffffb4 - r[0]; c = o[0] >> 51; o[0] &= Mask;
|
||||
o[1] = l[1] + 0x1ffffffffffffc - r[1] + c; c = o[1] >> 51; o[1] &= Mask;
|
||||
o[2] = l[2] + 0x1ffffffffffffc - r[2] + c; c = o[2] >> 51; o[2] &= Mask;
|
||||
o[3] = l[3] + 0x1ffffffffffffc - r[3] + c; c = o[3] >> 51; o[3] &= Mask;
|
||||
o[4] = l[4] + 0x1ffffffffffffc - r[4] + c; c = o[4] >> 51; o[4] &= Mask;
|
||||
o[0] += c * 19;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline auto operator*(const Modulo25519& l, uint64_t scalar) -> Modulo25519 {
|
||||
Modulo25519 o;
|
||||
uint128_t a;
|
||||
a = (uint128_t)l[0] * scalar; o[0] = a & Mask;
|
||||
a = (uint128_t)l[1] * scalar + (a >> 51 & Mask); o[1] = a & Mask;
|
||||
a = (uint128_t)l[2] * scalar + (a >> 51 & Mask); o[2] = a & Mask;
|
||||
a = (uint128_t)l[3] * scalar + (a >> 51 & Mask); o[3] = a & Mask;
|
||||
a = (uint128_t)l[4] * scalar + (a >> 51 & Mask); o[4] = a & Mask;
|
||||
o[0] += (a >> 51) * 19;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline auto operator*(const Modulo25519& l, Modulo25519 r) -> Modulo25519 {
|
||||
uint128_t t[] = {
|
||||
(uint128_t)r[0] * l[0],
|
||||
(uint128_t)r[0] * l[1] + (uint128_t)r[1] * l[0],
|
||||
(uint128_t)r[0] * l[2] + (uint128_t)r[1] * l[1] + (uint128_t)r[2] * l[0],
|
||||
(uint128_t)r[0] * l[3] + (uint128_t)r[1] * l[2] + (uint128_t)r[2] * l[1] + (uint128_t)r[3] * l[0],
|
||||
(uint128_t)r[0] * l[4] + (uint128_t)r[1] * l[3] + (uint128_t)r[2] * l[2] + (uint128_t)r[3] * l[1] + (uint128_t)r[4] * l[0]
|
||||
};
|
||||
|
||||
r[1] *= 19, r[2] *= 19, r[3] *= 19, r[4] *= 19;
|
||||
|
||||
t[0] += (uint128_t)r[4] * l[1] + (uint128_t)r[3] * l[2] + (uint128_t)r[2] * l[3] + (uint128_t)r[1] * l[4];
|
||||
t[1] += (uint128_t)r[4] * l[2] + (uint128_t)r[3] * l[3] + (uint128_t)r[2] * l[4];
|
||||
t[2] += (uint128_t)r[4] * l[3] + (uint128_t)r[3] * l[4];
|
||||
t[3] += (uint128_t)r[4] * l[4];
|
||||
|
||||
uint64_t c; r[0] = t[0] & Mask; c = (uint64_t)(t[0] >> 51);
|
||||
t[1] += c; r[1] = t[1] & Mask; c = (uint64_t)(t[1] >> 51);
|
||||
t[2] += c; r[2] = t[2] & Mask; c = (uint64_t)(t[2] >> 51);
|
||||
t[3] += c; r[3] = t[3] & Mask; c = (uint64_t)(t[3] >> 51);
|
||||
t[4] += c; r[4] = t[4] & Mask; c = (uint64_t)(t[4] >> 51);
|
||||
|
||||
r[0] += c * 19; c = r[0] >> 51; r[0] &= Mask;
|
||||
r[1] += c; c = r[1] >> 51; r[1] &= Mask;
|
||||
r[2] += c;
|
||||
return r;
|
||||
}
|
||||
|
||||
inline auto operator&(const Modulo25519& lhs, uint256_t rhs) -> uint256_t {
|
||||
return lhs() & rhs;
|
||||
}
|
||||
|
||||
inline auto square(const Modulo25519& lhs) -> Modulo25519 {
|
||||
Modulo25519 r{lhs};
|
||||
Modulo25519 d{r[0] * 2, r[1] * 2, r[2] * 2 * 19, r[4] * 19, r[4] * 19 * 2};
|
||||
|
||||
uint128_t t[5];
|
||||
t[0] = (uint128_t)r[0] * r[0] + (uint128_t)d[4] * r[1] + (uint128_t)d[2] * r[3];
|
||||
t[1] = (uint128_t)d[0] * r[1] + (uint128_t)d[4] * r[2] + (uint128_t)r[3] * r[3] * 19;
|
||||
t[2] = (uint128_t)d[0] * r[2] + (uint128_t)r[1] * r[1] + (uint128_t)d[4] * r[3];
|
||||
t[3] = (uint128_t)d[0] * r[3] + (uint128_t)d[1] * r[2] + (uint128_t)r[4] * d[3];
|
||||
t[4] = (uint128_t)d[0] * r[4] + (uint128_t)d[1] * r[3] + (uint128_t)r[2] * r[2];
|
||||
|
||||
uint64_t c; r[0] = t[0] & Mask; c = (uint64_t)(t[0] >> 51);
|
||||
t[1] += c; r[1] = t[1] & Mask; c = (uint64_t)(t[1] >> 51);
|
||||
t[2] += c; r[2] = t[2] & Mask; c = (uint64_t)(t[2] >> 51);
|
||||
t[3] += c; r[3] = t[3] & Mask; c = (uint64_t)(t[3] >> 51);
|
||||
t[4] += c; r[4] = t[4] & Mask; c = (uint64_t)(t[4] >> 51);
|
||||
|
||||
r[0] += c * 19; c = r[0] >> 51; r[0] &= Mask;
|
||||
r[1] += c; c = r[1] >> 51; r[1] &= Mask;
|
||||
r[2] += c;
|
||||
return r;
|
||||
}
|
||||
|
||||
inline auto exponentiate(const Modulo25519& lhs, uint256_t exponent) -> Modulo25519 {
|
||||
Modulo25519 x = 1, y;
|
||||
for(uint bit : reverse(range(256))) {
|
||||
x = square(x);
|
||||
y = x * lhs;
|
||||
cmove(exponent >> bit & 1, x, y);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline auto reciprocal(const Modulo25519& lhs) -> Modulo25519 {
|
||||
return exponentiate(lhs, P - 2);
|
||||
}
|
||||
|
||||
inline auto squareRoot(const Modulo25519& lhs) -> Modulo25519 {
|
||||
static const Modulo25519 I = exponentiate(Modulo25519(2), P - 1 >> 2); //I == sqrt(-1)
|
||||
Modulo25519 x = exponentiate(lhs, P + 3 >> 3);
|
||||
Modulo25519 y = x * I;
|
||||
cmove(bool(square(x) - lhs), x, y);
|
||||
y = -x;
|
||||
cmove(x & 1, x, y);
|
||||
return x;
|
||||
}
|
||||
|
||||
#undef Mask
|
||||
|
||||
}}
|
@ -1,79 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
//warning: this implementation leaks side-channel information
|
||||
//use modulo25519-optimized.hpp in production
|
||||
|
||||
#include <nall/arithmetic/barrett.hpp>
|
||||
|
||||
namespace nall { namespace EllipticCurve {
|
||||
|
||||
static const uint256_t P = (1_u256 << 255) - 19;
|
||||
static const uint256_t L = (1_u256 << 252) + 27742317777372353535851937790883648493_u256;
|
||||
|
||||
static BarrettReduction modP{P};
|
||||
static BarrettReduction modL{L};
|
||||
struct Modulo25519 {
|
||||
inline Modulo25519() = default;
|
||||
inline Modulo25519(const Modulo25519& source) : value(source.value) {}
|
||||
template<typename T> inline Modulo25519(const T& value) : value(value) {}
|
||||
inline explicit operator bool() const { return (bool)value; }
|
||||
inline auto operator()() const -> uint256_t { return value; }
|
||||
|
||||
struct Modulo25519 : uint256_t {
|
||||
using type = Modulo25519;
|
||||
using uint256_t::uint256_t;
|
||||
|
||||
alwaysinline auto operator()() const -> uint256_t {
|
||||
return *this;
|
||||
}
|
||||
|
||||
alwaysinline auto operator-() const -> type {
|
||||
return P.operator-(*this);
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto operator+(const T& rhs) const -> type {
|
||||
auto lhs = (uint512_t)*this + rhs;
|
||||
if(lhs >= P) lhs -= P;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto operator-(const T& rhs) const -> type {
|
||||
auto lhs = (uint512_t)*this;
|
||||
if(lhs < rhs) lhs += P;
|
||||
return lhs - rhs;
|
||||
}
|
||||
|
||||
template<typename T> alwaysinline auto operator*(const T& rhs) const -> type {
|
||||
uint256_t hi, lo;
|
||||
nall::mul(*this, rhs, hi, lo);
|
||||
return modP(uint512_t{hi, lo});
|
||||
}
|
||||
|
||||
alwaysinline auto square() const -> type {
|
||||
uint256_t hi, lo;
|
||||
nall::square(*this, hi, lo);
|
||||
return modP(uint512_t{hi, lo});
|
||||
}
|
||||
|
||||
inline auto expmod(uint256_t e) const -> type {
|
||||
type x = 1;
|
||||
for(auto n : rrange(256)) {
|
||||
x = x.square();
|
||||
if(e >> n & 1) x = operator*(x);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline auto reciprocal() const -> type {
|
||||
return expmod(P - 2);
|
||||
}
|
||||
|
||||
inline auto squareRoot() const -> type {
|
||||
static const type i = type(2).expmod((P - 1) >> 2); //i = sqrt(-1)
|
||||
type x = expmod((P + 3) >> 3);
|
||||
if(operator!=(x.square())) x = x * i;
|
||||
if(x & 1) x = -x;
|
||||
return x;
|
||||
}
|
||||
private:
|
||||
uint256_t value;
|
||||
};
|
||||
|
||||
inline auto cmove(bool bit, Modulo25519& lhs, const Modulo25519& rhs) -> void {
|
||||
if(bit) lhs = rhs;
|
||||
inline auto operator-(const Modulo25519& lhs) -> Modulo25519 {
|
||||
return P - lhs();
|
||||
}
|
||||
|
||||
inline auto cswap(bool bit, Modulo25519& lhs, Modulo25519& rhs) -> void {
|
||||
if(bit) swap(lhs, rhs);
|
||||
inline auto operator+(const Modulo25519& lhs, const Modulo25519& rhs) -> Modulo25519 {
|
||||
uint512_t value = (uint512_t)lhs() + rhs();
|
||||
if(value >= P) value -= P;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline auto operator-(const Modulo25519& lhs, const Modulo25519& rhs) -> Modulo25519 {
|
||||
uint512_t value = (uint512_t)lhs();
|
||||
if(value < rhs()) value += P;
|
||||
return uint256_t(value - rhs());
|
||||
}
|
||||
|
||||
inline auto operator*(const Modulo25519& lhs, const Modulo25519& rhs) -> Modulo25519 {
|
||||
static const BarrettReduction<256> P{EllipticCurve::P};
|
||||
uint256_t hi, lo;
|
||||
mul(lhs(), rhs(), hi, lo);
|
||||
return uint512_t{hi, lo} % P;
|
||||
}
|
||||
|
||||
inline auto operator&(const Modulo25519& lhs, uint256_t rhs) -> uint256_t {
|
||||
return lhs() & rhs;
|
||||
}
|
||||
|
||||
inline auto square(const Modulo25519& lhs) -> Modulo25519 {
|
||||
static const BarrettReduction<256> P{EllipticCurve::P};
|
||||
uint256_t hi, lo;
|
||||
square(lhs(), hi, lo);
|
||||
return uint512_t{hi, lo} % P;
|
||||
}
|
||||
|
||||
inline auto exponentiate(const Modulo25519& lhs, uint256_t exponent) -> Modulo25519 {
|
||||
if(exponent == 0) return 1;
|
||||
Modulo25519 value = square(exponentiate(lhs, exponent >> 1));
|
||||
if(exponent & 1) value = value * lhs;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline auto reciprocal(const Modulo25519& lhs) -> Modulo25519 {
|
||||
return exponentiate(lhs, P - 2);
|
||||
}
|
||||
|
||||
inline auto squareRoot(const Modulo25519& lhs) -> Modulo25519 {
|
||||
static const Modulo25519 I = exponentiate(Modulo25519(2), P - 1 >> 2); //I = sqrt(-1)
|
||||
Modulo25519 value = exponentiate(lhs, P + 3 >> 3);
|
||||
if(square(value) - lhs) value = value * I;
|
||||
if(value & 1) value = -value;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline auto cmove(bool condition, Modulo25519& lhs, const Modulo25519& rhs) -> void {
|
||||
if(condition) lhs = rhs;
|
||||
}
|
||||
|
||||
inline auto cswap(bool condition, Modulo25519& lhs, Modulo25519& rhs) -> void {
|
||||
if(condition) swap(lhs, rhs);
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -1,234 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/arithmetic/barrett.hpp>
|
||||
|
||||
namespace nall { namespace EllipticCurve {
|
||||
|
||||
static const uint256_t P = (1_u256 << 255) - 19;
|
||||
static const uint256_t L = (1_u256 << 252) + 27742317777372353535851937790883648493_u256;
|
||||
|
||||
static BarrettReduction modP{P};
|
||||
static BarrettReduction modL{L};
|
||||
|
||||
struct Modulo25519;
|
||||
auto cmove(bool move, Modulo25519& l, const Modulo25519& r) -> void;
|
||||
auto cswap(bool swap, Modulo25519& l, Modulo25519& r) -> void;
|
||||
|
||||
struct Modulo25519 {
|
||||
using type = Modulo25519;
|
||||
#define Mask ((1ull << 51) - 1)
|
||||
|
||||
inline Modulo25519() = default;
|
||||
inline Modulo25519(const Modulo25519&) = default;
|
||||
inline Modulo25519(uint64_t a, uint64_t b = 0, uint64_t c = 0, uint64_t d = 0, uint64_t e = 0) : l{a, b, c, d, e} {}
|
||||
|
||||
inline Modulo25519(uint256_t n) {
|
||||
l[0] = n >> 0 & Mask;
|
||||
l[1] = n >> 51 & Mask;
|
||||
l[2] = n >> 102 & Mask;
|
||||
l[3] = n >> 153 & Mask;
|
||||
l[4] = n >> 204 & Mask;
|
||||
}
|
||||
|
||||
inline auto operator()() const -> uint256_t { return operator uint256_t(); }
|
||||
inline auto& operator[](uint index) { return l[index]; }
|
||||
inline auto operator[](uint index) const { return l[index]; }
|
||||
|
||||
inline explicit operator bool() const {
|
||||
return operator uint256_t();
|
||||
}
|
||||
|
||||
inline operator uint256_t() const {
|
||||
type o = *this;
|
||||
|
||||
o[1] += (o[0] >> 51); o[0] &= Mask;
|
||||
o[2] += (o[1] >> 51); o[1] &= Mask;
|
||||
o[3] += (o[2] >> 51); o[2] &= Mask;
|
||||
o[4] += (o[3] >> 51); o[3] &= Mask;
|
||||
o[0] += 19 * (o[4] >> 51); o[4] &= Mask;
|
||||
|
||||
o[1] += (o[0] >> 51); o[0] &= Mask;
|
||||
o[2] += (o[1] >> 51); o[1] &= Mask;
|
||||
o[3] += (o[2] >> 51); o[2] &= Mask;
|
||||
o[4] += (o[3] >> 51); o[3] &= Mask;
|
||||
o[0] += 19 * (o[4] >> 51); o[4] &= Mask;
|
||||
|
||||
o[0] += 19;
|
||||
o[1] += (o[0] >> 51); o[0] &= Mask;
|
||||
o[2] += (o[1] >> 51); o[1] &= Mask;
|
||||
o[3] += (o[2] >> 51); o[2] &= Mask;
|
||||
o[4] += (o[3] >> 51); o[3] &= Mask;
|
||||
o[0] += 19 * (o[4] >> 51); o[4] &= Mask;
|
||||
|
||||
o[0] += Mask - 18;
|
||||
o[1] += Mask;
|
||||
o[2] += Mask;
|
||||
o[3] += Mask;
|
||||
o[4] += Mask;
|
||||
|
||||
o[1] += o[0] >> 51; o[0] &= Mask;
|
||||
o[2] += o[1] >> 51; o[1] &= Mask;
|
||||
o[3] += o[2] >> 51; o[2] &= Mask;
|
||||
o[4] += o[3] >> 51; o[3] &= Mask;
|
||||
o[4] &= Mask;
|
||||
|
||||
return (uint256_t)o[0] << 0 | (uint256_t)o[1] << 51 | (uint256_t)o[2] << 102 | (uint256_t)o[3] << 153 | (uint256_t)o[4] << 204;
|
||||
}
|
||||
|
||||
inline auto operator!=(type r) const -> bool {
|
||||
bool e = 1;
|
||||
e &= l[0] == r[0];
|
||||
e &= l[1] == r[1];
|
||||
e &= l[2] == r[2];
|
||||
e &= l[3] == r[3];
|
||||
e &= l[4] == r[4];
|
||||
return e == 0;
|
||||
}
|
||||
|
||||
inline auto operator-() const -> type { //P - l
|
||||
type o;
|
||||
uint64_t c;
|
||||
o[0] = 0xfffffffffffda - l[0]; c = o[0] >> 51; o[0] &= Mask;
|
||||
o[1] = 0xffffffffffffe - l[1] + c; c = o[1] >> 51; o[1] &= Mask;
|
||||
o[2] = 0xffffffffffffe - l[2] + c; c = o[2] >> 51; o[2] &= Mask;
|
||||
o[3] = 0xffffffffffffe - l[3] + c; c = o[3] >> 51; o[3] &= Mask;
|
||||
o[4] = 0xffffffffffffe - l[4] + c; c = o[4] >> 51; o[4] &= Mask;
|
||||
o[0] += c * 19;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline auto operator+(type r) const -> type {
|
||||
type o;
|
||||
uint64_t c;
|
||||
o[0] = l[0] + r[0]; c = o[0] >> 51; o[0] &= Mask;
|
||||
o[1] = l[1] + r[1] + c; c = o[1] >> 51; o[1] &= Mask;
|
||||
o[2] = l[2] + r[2] + c; c = o[2] >> 51; o[2] &= Mask;
|
||||
o[3] = l[3] + r[3] + c; c = o[3] >> 51; o[3] &= Mask;
|
||||
o[4] = l[4] + r[4] + c; c = o[4] >> 51; o[4] &= Mask;
|
||||
o[0] += c * 19;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline auto operator-(type r) const -> type {
|
||||
type o;
|
||||
uint64_t c;
|
||||
o[0] = l[0] + 0x1fffffffffffb4 - r[0]; c = o[0] >> 51; o[0] &= Mask;
|
||||
o[1] = l[1] + 0x1ffffffffffffc - r[1] + c; c = o[1] >> 51; o[1] &= Mask;
|
||||
o[2] = l[2] + 0x1ffffffffffffc - r[2] + c; c = o[2] >> 51; o[2] &= Mask;
|
||||
o[3] = l[3] + 0x1ffffffffffffc - r[3] + c; c = o[3] >> 51; o[3] &= Mask;
|
||||
o[4] = l[4] + 0x1ffffffffffffc - r[4] + c; c = o[4] >> 51; o[4] &= Mask;
|
||||
o[0] += c * 19;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline auto operator*(uint64_t scalar) const -> type {
|
||||
type o;
|
||||
uint128_t a;
|
||||
a = (uint128_t)l[0] * scalar; o[0] = a & Mask;
|
||||
a = (uint128_t)l[1] * scalar + (a >> 51 & Mask); o[1] = a & Mask;
|
||||
a = (uint128_t)l[2] * scalar + (a >> 51 & Mask); o[2] = a & Mask;
|
||||
a = (uint128_t)l[3] * scalar + (a >> 51 & Mask); o[3] = a & Mask;
|
||||
a = (uint128_t)l[4] * scalar + (a >> 51 & Mask); o[4] = a & Mask;
|
||||
o[0] += (a >> 51) * 19;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline auto operator*(type r) const -> type {
|
||||
uint128_t t[] = {
|
||||
(uint128_t)r[0] * l[0],
|
||||
(uint128_t)r[0] * l[1] + (uint128_t)r[1] * l[0],
|
||||
(uint128_t)r[0] * l[2] + (uint128_t)r[1] * l[1] + (uint128_t)r[2] * l[0],
|
||||
(uint128_t)r[0] * l[3] + (uint128_t)r[1] * l[2] + (uint128_t)r[2] * l[1] + (uint128_t)r[3] * l[0],
|
||||
(uint128_t)r[0] * l[4] + (uint128_t)r[1] * l[3] + (uint128_t)r[2] * l[2] + (uint128_t)r[3] * l[1] + (uint128_t)r[4] * l[0]
|
||||
};
|
||||
|
||||
r[1] *= 19, r[2] *= 19, r[3] *= 19, r[4] *= 19;
|
||||
|
||||
t[0] += (uint128_t)r[4] * l[1] + (uint128_t)r[3] * l[2] + (uint128_t)r[2] * l[3] + (uint128_t)r[1] * l[4];
|
||||
t[1] += (uint128_t)r[4] * l[2] + (uint128_t)r[3] * l[3] + (uint128_t)r[2] * l[4];
|
||||
t[2] += (uint128_t)r[4] * l[3] + (uint128_t)r[3] * l[4];
|
||||
t[3] += (uint128_t)r[4] * l[4];
|
||||
|
||||
uint64_t c; r[0] = t[0] & Mask; c = (uint64_t)(t[0] >> 51);
|
||||
t[1] += c; r[1] = t[1] & Mask; c = (uint64_t)(t[1] >> 51);
|
||||
t[2] += c; r[2] = t[2] & Mask; c = (uint64_t)(t[2] >> 51);
|
||||
t[3] += c; r[3] = t[3] & Mask; c = (uint64_t)(t[3] >> 51);
|
||||
t[4] += c; r[4] = t[4] & Mask; c = (uint64_t)(t[4] >> 51);
|
||||
|
||||
r[0] += c * 19; c = r[0] >> 51; r[0] &= Mask;
|
||||
r[1] += c; c = r[1] >> 51; r[1] &= Mask;
|
||||
r[2] += c;
|
||||
return r;
|
||||
}
|
||||
|
||||
inline auto square() const -> type {
|
||||
type r{*this};
|
||||
type d{r[0] * 2, r[1] * 2, r[2] * 2 * 19, r[4] * 19, r[4] * 19 * 2};
|
||||
|
||||
uint128_t t[5];
|
||||
t[0] = (uint128_t)r[0] * r[0] + (uint128_t)d[4] * r[1] + (uint128_t)d[2] * r[3];
|
||||
t[1] = (uint128_t)d[0] * r[1] + (uint128_t)d[4] * r[2] + (uint128_t)r[3] * r[3] * 19;
|
||||
t[2] = (uint128_t)d[0] * r[2] + (uint128_t)r[1] * r[1] + (uint128_t)d[4] * r[3];
|
||||
t[3] = (uint128_t)d[0] * r[3] + (uint128_t)d[1] * r[2] + (uint128_t)r[4] * d[3];
|
||||
t[4] = (uint128_t)d[0] * r[4] + (uint128_t)d[1] * r[3] + (uint128_t)r[2] * r[2];
|
||||
|
||||
uint64_t c; r[0] = t[0] & Mask; c = (uint64_t)(t[0] >> 51);
|
||||
t[1] += c; r[1] = t[1] & Mask; c = (uint64_t)(t[1] >> 51);
|
||||
t[2] += c; r[2] = t[2] & Mask; c = (uint64_t)(t[2] >> 51);
|
||||
t[3] += c; r[3] = t[3] & Mask; c = (uint64_t)(t[3] >> 51);
|
||||
t[4] += c; r[4] = t[4] & Mask; c = (uint64_t)(t[4] >> 51);
|
||||
|
||||
r[0] += c * 19; c = r[0] >> 51; r[0] &= Mask;
|
||||
r[1] += c; c = r[1] >> 51; r[1] &= Mask;
|
||||
r[2] += c;
|
||||
return r;
|
||||
}
|
||||
|
||||
inline auto expmod(uint256_t e) const -> type {
|
||||
type x = 1, y;
|
||||
for(uint n : reverse(range(256))) {
|
||||
x = x.square();
|
||||
y = operator*(x);
|
||||
cmove(e >> n & 1, x, y);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline auto reciprocal() const -> type {
|
||||
return expmod(P - 2);
|
||||
}
|
||||
|
||||
inline auto squareRoot() const -> type {
|
||||
static const type i = type(2).expmod((P - 1) >> 2); //i == sqrt(-1)
|
||||
type x = expmod((P + 3) >> 3);
|
||||
type y = x * i;
|
||||
cmove(operator!=(x.square()), x, y);
|
||||
y = -x;
|
||||
cmove(x() & 1, x, y);
|
||||
return x;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t l[5]; //51-bits per limb; 255-bits total
|
||||
#undef Mask
|
||||
};
|
||||
|
||||
inline auto cmove(bool move, Modulo25519& l, const Modulo25519& r) -> void {
|
||||
uint64_t mask = -move;
|
||||
l[0] ^= mask & (l[0] ^ r[0]);
|
||||
l[1] ^= mask & (l[1] ^ r[1]);
|
||||
l[2] ^= mask & (l[2] ^ r[2]);
|
||||
l[3] ^= mask & (l[3] ^ r[3]);
|
||||
l[4] ^= mask & (l[4] ^ r[4]);
|
||||
}
|
||||
|
||||
inline auto cswap(bool swap, Modulo25519& l, Modulo25519& r) -> void {
|
||||
uint64_t mask = -swap, x;
|
||||
x = mask & (l[0] ^ r[0]); l[0] ^= x; r[0] ^= x;
|
||||
x = mask & (l[1] ^ r[1]); l[1] ^= x; r[1] ^= x;
|
||||
x = mask & (l[2] ^ r[2]); l[2] ^= x; r[2] ^= x;
|
||||
x = mask & (l[3] ^ r[3]); l[3] ^= x; r[3] ^= x;
|
||||
x = mask & (l[4] ^ r[4]); l[4] ^= x; r[4] ^= x;
|
||||
}
|
||||
|
||||
}}
|
@ -17,7 +17,7 @@ using uint32 = Natural<32>;
|
||||
using uint64 = Natural<64>;
|
||||
|
||||
struct FX {
|
||||
auto open(vector<string> arguments) -> bool;
|
||||
auto open(Arguments& arguments) -> bool;
|
||||
auto close() -> void;
|
||||
auto readable() -> bool;
|
||||
auto read() -> uint8_t;
|
||||
@ -35,16 +35,10 @@ struct FX {
|
||||
serial device;
|
||||
};
|
||||
|
||||
auto FX::open(vector<string> arguments) -> bool {
|
||||
auto FX::open(Arguments& arguments) -> bool {
|
||||
//device name override support
|
||||
string name;
|
||||
for(auto argument : arguments) {
|
||||
if(argument.beginsWith("--device=")) {
|
||||
name = argument.trimLeft("--device=", 1L);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
arguments.take("--device", name);
|
||||
if(!device.open(name)) {
|
||||
print("[21fx] error: unable to open hardware device\n");
|
||||
return false;
|
||||
|
@ -4,7 +4,7 @@ namespace nall { namespace Encode {
|
||||
|
||||
struct BMP {
|
||||
static auto create(const string& filename, const void* data, uint pitch, uint width, uint height, bool alpha) -> bool {
|
||||
file fp{filename, file::mode::write};
|
||||
auto fp = file::open(filename, file::mode::write);
|
||||
if(!fp) return false;
|
||||
|
||||
uint bitsPerPixel = alpha ? 32 : 24;
|
||||
|
@ -49,14 +49,14 @@ inline auto LZSA(array_view<uint8_t> input) -> vector<uint8_t> {
|
||||
int length, offset;
|
||||
suffixArray.previous(length, offset, index);
|
||||
|
||||
for(uint ahead = 1; ahead <= 2; ahead++) {
|
||||
/* for(uint ahead = 1; ahead <= 2; ahead++) {
|
||||
int aheadLength, aheadOffset;
|
||||
suffixArray.previous(aheadLength, aheadOffset, index + ahead);
|
||||
if(aheadLength > length && aheadOffset >= 0) {
|
||||
length = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
if(length < 6 || offset < 0) {
|
||||
flagWrite(0);
|
||||
|
@ -19,7 +19,7 @@ struct ZIP {
|
||||
filename.transform("\\", "/");
|
||||
if(!timestamp) timestamp = this->timestamp;
|
||||
uint32_t checksum = Hash::CRC32({data, size}).digest().hex();
|
||||
directory.append({filename, timestamp, checksum, size, fp.offset()});
|
||||
directory.append({filename, timestamp, checksum, size, (uint32_t)fp.offset()});
|
||||
|
||||
fp.writel(0x04034b50, 4); //signature
|
||||
fp.writel(0x0014, 2); //minimum version (2.0)
|
||||
@ -34,7 +34,7 @@ struct ZIP {
|
||||
fp.writel(0x0000, 2); //extra field length
|
||||
fp.print(filename); //file name
|
||||
|
||||
fp.write(data, size); //file data
|
||||
fp.write({data, size}); //file data
|
||||
}
|
||||
|
||||
~ZIP() {
|
||||
@ -86,7 +86,7 @@ protected:
|
||||
return ((info->tm_year - 80) << 9) | ((1 + info->tm_mon) << 5) + (info->tm_mday);
|
||||
}
|
||||
|
||||
file fp;
|
||||
file_buffer fp;
|
||||
time_t timestamp;
|
||||
struct entry_t {
|
||||
string filename;
|
||||
|
249
nall/file-buffer.hpp
Normal file
249
nall/file-buffer.hpp
Normal file
@ -0,0 +1,249 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/array-span.hpp>
|
||||
#include <nall/array-view.hpp>
|
||||
#include <nall/inode.hpp>
|
||||
#include <nall/range.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/hash/sha256.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
//on Windows (at least for 7 and earlier), FILE* is not buffered
|
||||
//thus, reading/writing one byte at a time will be dramatically slower
|
||||
//on all other OSes, FILE* is buffered
|
||||
//in order to ensure good performance, file_buffer implements its own buffer
|
||||
//this speeds up Windows substantially, without harming performance elsewhere much
|
||||
|
||||
struct file_buffer {
|
||||
struct mode { enum : uint { read, write, modify, append }; };
|
||||
struct index { enum : uint { absolute, relative }; };
|
||||
|
||||
file_buffer(const file_buffer&) = delete;
|
||||
auto operator=(const file_buffer&) -> file_buffer& = delete;
|
||||
|
||||
file_buffer() = default;
|
||||
file_buffer(const string& filename, uint mode) { open(filename, mode); }
|
||||
|
||||
file_buffer(file_buffer&& source) { operator=(move(source)); }
|
||||
|
||||
~file_buffer() { close(); }
|
||||
|
||||
auto operator=(file_buffer&& source) -> file_buffer& {
|
||||
buffer = source.buffer;
|
||||
bufferOffset = source.bufferOffset;
|
||||
bufferDirty = source.bufferDirty;
|
||||
fileHandle = source.fileHandle;
|
||||
fileOffset = source.fileOffset;
|
||||
fileSize = source.fileSize;
|
||||
fileMode = source.fileMode;
|
||||
|
||||
source.bufferOffset = -1;
|
||||
source.bufferDirty = false;
|
||||
source.fileHandle = nullptr;
|
||||
source.fileOffset = 0;
|
||||
source.fileSize = 0;
|
||||
source.fileMode = mode::read;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return (bool)fileHandle;
|
||||
}
|
||||
|
||||
auto read() -> uint8_t {
|
||||
if(!fileHandle) return 0; //file not open
|
||||
if(fileMode == mode::write) return 0; //reads not permitted
|
||||
if(fileOffset >= fileSize) return 0; //cannot read past end of file
|
||||
bufferSynchronize();
|
||||
return buffer[fileOffset++ & buffer.size() - 1];
|
||||
}
|
||||
|
||||
template<typename T = uint64_t> auto readl(uint length = 1) -> T {
|
||||
T data = 0;
|
||||
for(uint n : range(length)) {
|
||||
data |= (T)read() << n * 8;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename T = uint64_t> auto readm(uint length = 1) -> T {
|
||||
T data = 0;
|
||||
while(length--) {
|
||||
data <<= 8;
|
||||
data |= read();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
auto reads(uint length) -> string {
|
||||
string result;
|
||||
result.resize(length);
|
||||
for(auto& byte : result) byte = read();
|
||||
return result;
|
||||
}
|
||||
|
||||
auto read(array_span<uint8_t> memory) -> void {
|
||||
for(auto& byte : memory) byte = read();
|
||||
}
|
||||
|
||||
auto write(uint8_t data) -> void {
|
||||
if(!fileHandle) return; //file not open
|
||||
if(fileMode == mode::read) return; //writes not permitted
|
||||
bufferSynchronize();
|
||||
buffer[fileOffset++ & buffer.size() - 1] = data;
|
||||
bufferDirty = true;
|
||||
if(fileOffset > fileSize) fileSize = fileOffset;
|
||||
}
|
||||
|
||||
template<typename T = uint64_t> auto writel(T data, uint length = 1) -> void {
|
||||
while(length--) {
|
||||
write(uint8_t(data));
|
||||
data >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T = uint64_t> auto writem(T data, uint length = 1) -> void {
|
||||
for(uint n : reverse(range(length))) {
|
||||
write(uint8_t(data >> n * 8));
|
||||
}
|
||||
}
|
||||
|
||||
auto writes(const string& s) -> void {
|
||||
for(auto& byte : s) write(byte);
|
||||
}
|
||||
|
||||
auto write(array_view<uint8_t> memory) -> void {
|
||||
for(auto& byte : memory) write(byte);
|
||||
}
|
||||
|
||||
template<typename... P> auto print(P&&... p) -> void {
|
||||
string s{forward<P>(p)...};
|
||||
for(auto& byte : s) write(byte);
|
||||
}
|
||||
|
||||
auto flush() -> void {
|
||||
bufferFlush();
|
||||
fflush(fileHandle);
|
||||
}
|
||||
|
||||
auto seek(int64_t offset, uint index_ = index::absolute) -> void {
|
||||
if(!fileHandle) return;
|
||||
bufferFlush();
|
||||
|
||||
int64_t seekOffset = fileOffset;
|
||||
switch(index_) {
|
||||
case index::absolute: seekOffset = offset; break;
|
||||
case index::relative: seekOffset += offset; break;
|
||||
}
|
||||
|
||||
if(seekOffset < 0) seekOffset = 0; //cannot seek before start of file
|
||||
if(seekOffset > fileSize) {
|
||||
if(fileMode == mode::read) { //cannot seek past end of file
|
||||
seekOffset = fileSize;
|
||||
} else { //pad file to requested location
|
||||
fileOffset = fileSize;
|
||||
while(fileSize < seekOffset) write(0);
|
||||
}
|
||||
}
|
||||
|
||||
fileOffset = seekOffset;
|
||||
}
|
||||
|
||||
auto offset() const -> uint64_t {
|
||||
if(!fileHandle) return 0;
|
||||
return fileOffset;
|
||||
}
|
||||
|
||||
auto size() const -> uint64_t {
|
||||
if(!fileHandle) return 0;
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
auto truncate(uint64_t size) -> bool {
|
||||
if(!fileHandle) return false;
|
||||
#if defined(API_POSIX)
|
||||
return ftruncate(fileno(fileHandle), size) == 0;
|
||||
#elif defined(API_WINDOWS)
|
||||
return _chsize(fileno(fileHandle), size) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
auto end() const -> bool {
|
||||
if(!fileHandle) return true;
|
||||
return fileOffset >= fileSize;
|
||||
}
|
||||
|
||||
auto open(const string& filename, uint mode_) -> bool {
|
||||
close();
|
||||
|
||||
switch(fileMode = mode_) {
|
||||
#if defined(API_POSIX)
|
||||
case mode::read: fileHandle = fopen(filename, "rb" ); break;
|
||||
case mode::write: fileHandle = fopen(filename, "wb+"); break; //need read permission for buffering
|
||||
case mode::modify: fileHandle = fopen(filename, "rb+"); break;
|
||||
case mode::append: fileHandle = fopen(filename, "wb+"); break;
|
||||
#elif defined(API_WINDOWS)
|
||||
case mode::read: fileHandle = _wfopen(utf16_t(filename), L"rb" ); break;
|
||||
case mode::write: fileHandle = _wfopen(utf16_t(filename), L"wb+"); break;
|
||||
case mode::modify: fileHandle = _wfopen(utf16_t(filename), L"rb+"); break;
|
||||
case mode::append: fileHandle = _wfopen(utf16_t(filename), L"wb+"); break;
|
||||
#endif
|
||||
}
|
||||
if(!fileHandle) return false;
|
||||
|
||||
bufferOffset = -1;
|
||||
fileOffset = 0;
|
||||
fseek(fileHandle, 0, SEEK_END);
|
||||
fileSize = ftell(fileHandle);
|
||||
fseek(fileHandle, 0, SEEK_SET);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto close() -> void {
|
||||
if(!fileHandle) return;
|
||||
bufferFlush();
|
||||
fclose(fileHandle);
|
||||
fileHandle = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
array<uint8_t[4096]> buffer;
|
||||
int bufferOffset = -1;
|
||||
bool bufferDirty = false;
|
||||
FILE* fileHandle = nullptr;
|
||||
uint64_t fileOffset = 0;
|
||||
uint64_t fileSize = 0;
|
||||
uint fileMode = mode::read;
|
||||
|
||||
auto bufferSynchronize() -> void {
|
||||
if(!fileHandle) return;
|
||||
if(bufferOffset == (fileOffset & ~(buffer.size() - 1))) return;
|
||||
|
||||
bufferFlush();
|
||||
bufferOffset = fileOffset & ~(buffer.size() - 1);
|
||||
fseek(fileHandle, bufferOffset, SEEK_SET);
|
||||
uint64_t length = bufferOffset + buffer.size() <= fileSize ? buffer.size() : fileSize & buffer.size() - 1;
|
||||
if(length) (void)fread(buffer.data(), 1, length, fileHandle);
|
||||
}
|
||||
|
||||
auto bufferFlush() -> void {
|
||||
if(!fileHandle) return; //file not open
|
||||
if(fileMode == mode::read) return; //buffer cannot be written to
|
||||
if(bufferOffset < 0) return; //buffer unused
|
||||
if(!bufferDirty) return; //buffer unmodified since read
|
||||
|
||||
fseek(fileHandle, bufferOffset, SEEK_SET);
|
||||
uint64_t length = bufferOffset + buffer.size() <= fileSize ? buffer.size() : fileSize & buffer.size() - 1;
|
||||
if(length) (void)fwrite(buffer.data(), 1, length, fileHandle);
|
||||
bufferOffset = -1;
|
||||
bufferDirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
215
nall/file-map.hpp
Normal file
215
nall/file-map.hpp
Normal file
@ -0,0 +1,215 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
#include <nall/windows/utf8.hpp>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct file_map {
|
||||
struct mode { enum : uint { read, write, modify, append }; };
|
||||
|
||||
file_map(const file_map&) = delete;
|
||||
auto operator=(const file_map&) = delete;
|
||||
|
||||
file_map() = default;
|
||||
file_map(file_map&& source) { operator=(move(source)); }
|
||||
file_map(const string& filename, uint mode) { open(filename, mode); }
|
||||
|
||||
~file_map() { close(); }
|
||||
|
||||
explicit operator bool() const { return _open; }
|
||||
auto size() const -> uint64_t { return _size; }
|
||||
auto data() -> uint8_t* { return _data; }
|
||||
auto data() const -> const uint8_t* { return _data; }
|
||||
|
||||
//auto operator=(file_map&& source) -> file_map&;
|
||||
//auto open(const string& filename, uint mode) -> bool;
|
||||
//auto close() -> void;
|
||||
|
||||
private:
|
||||
bool _open = false;
|
||||
uint8_t* _data = nullptr;
|
||||
uint64_t _size = 0;
|
||||
|
||||
#if defined(API_WINDOWS)
|
||||
|
||||
HANDLE _file = INVALID_HANDLE_VALUE;
|
||||
HANDLE _map = INVALID_HANDLE_VALUE;
|
||||
|
||||
public:
|
||||
auto operator=(file_map&& source) -> file_map& {
|
||||
_open = source._open;
|
||||
_data = source._data;
|
||||
_size = source._size;
|
||||
_file = source._file;
|
||||
_map = source._map;
|
||||
|
||||
source._open = false;
|
||||
source._data = nullptr;
|
||||
source._size = 0;
|
||||
source._file = INVALID_HANDLE_VALUE;
|
||||
source._map = INVALID_HANDLE_VALUE;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto open(const string& filename, uint mode_) -> bool {
|
||||
int desiredAccess, creationDisposition, protection, mapAccess;
|
||||
|
||||
switch(mode_) {
|
||||
default: return false;
|
||||
case mode::read:
|
||||
desiredAccess = GENERIC_READ;
|
||||
creationDisposition = OPEN_EXISTING;
|
||||
protection = PAGE_READONLY;
|
||||
mapAccess = FILE_MAP_READ;
|
||||
break;
|
||||
case mode::write:
|
||||
//write access requires read access
|
||||
desiredAccess = GENERIC_WRITE;
|
||||
creationDisposition = CREATE_ALWAYS;
|
||||
protection = PAGE_READWRITE;
|
||||
mapAccess = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
case mode::modify:
|
||||
desiredAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
creationDisposition = OPEN_EXISTING;
|
||||
protection = PAGE_READWRITE;
|
||||
mapAccess = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
case mode::append:
|
||||
desiredAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
creationDisposition = CREATE_NEW;
|
||||
protection = PAGE_READWRITE;
|
||||
mapAccess = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
_file = CreateFileW(utf16_t(filename), desiredAccess, FILE_SHARE_READ, nullptr,
|
||||
creationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if(_file == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
_size = GetFileSize(_file, nullptr);
|
||||
|
||||
_map = CreateFileMapping(_file, nullptr, protection, 0, _size, nullptr);
|
||||
if(_map == INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(_file);
|
||||
_file = INVALID_HANDLE_VALUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
_data = (uint8_t*)MapViewOfFile(_map, mapAccess, 0, 0, _size);
|
||||
return _open = _data;
|
||||
}
|
||||
|
||||
auto close() -> void {
|
||||
if(_data) {
|
||||
UnmapViewOfFile(_data);
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
if(_map != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(_map);
|
||||
_map = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if(_file != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(_file);
|
||||
_file = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
_open = false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int _fd = -1;
|
||||
|
||||
public:
|
||||
auto operator=(file_map&& source) -> file_map& {
|
||||
_open = source._open;
|
||||
_data = source._data;
|
||||
_size = source._size;
|
||||
_fd = source._fd;
|
||||
|
||||
source._open = false;
|
||||
source._data = nullptr;
|
||||
source._size = 0;
|
||||
source._fd = -1;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto open(const string& filename, uint mode_) -> bool {
|
||||
close();
|
||||
int openFlags = 0;
|
||||
int mmapFlags = 0;
|
||||
|
||||
switch(mode_) {
|
||||
default: return false;
|
||||
case mode::read:
|
||||
openFlags = O_RDONLY;
|
||||
mmapFlags = PROT_READ;
|
||||
break;
|
||||
case mode::write:
|
||||
openFlags = O_RDWR | O_CREAT; //mmap() requires read access
|
||||
mmapFlags = PROT_WRITE;
|
||||
break;
|
||||
case mode::modify:
|
||||
openFlags = O_RDWR;
|
||||
mmapFlags = PROT_READ | PROT_WRITE;
|
||||
break;
|
||||
case mode::append:
|
||||
openFlags = O_RDWR | O_CREAT;
|
||||
mmapFlags = PROT_READ | PROT_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
_fd = ::open(filename, openFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
if(_fd < 0) return false;
|
||||
|
||||
struct stat _stat;
|
||||
fstat(_fd, &_stat);
|
||||
_size = _stat.st_size;
|
||||
|
||||
_data = (uint8_t*)mmap(nullptr, _size, mmapFlags, MAP_SHARED | MAP_NORESERVE, _fd, 0);
|
||||
if(_data == MAP_FAILED) {
|
||||
_data = nullptr;
|
||||
::close(_fd);
|
||||
_fd = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return _open = _data;
|
||||
}
|
||||
|
||||
auto close() -> void {
|
||||
if(_data) {
|
||||
munmap(_data, _size);
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
if(_fd >= 0) {
|
||||
::close(_fd);
|
||||
_fd = -1;
|
||||
}
|
||||
|
||||
_open = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
297
nall/file.hpp
297
nall/file.hpp
@ -1,26 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/inode.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/hash/sha256.hpp>
|
||||
#include <nall/file-buffer.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct file : inode, varint {
|
||||
enum class mode : uint { read, write, modify, append, readwrite = modify, writeread = append };
|
||||
enum class index : uint { absolute, relative };
|
||||
struct file : inode {
|
||||
struct mode { enum : uint { read, write, modify, append }; };
|
||||
struct index { enum : uint { absolute, relative }; };
|
||||
|
||||
file() = delete;
|
||||
|
||||
static auto open(const string& filename, uint mode) -> file_buffer {
|
||||
return file_buffer{filename, mode};
|
||||
}
|
||||
|
||||
static auto copy(const string& sourcename, const string& targetname) -> bool {
|
||||
if(sourcename == targetname) return true;
|
||||
file rd, wr;
|
||||
if(rd.open(sourcename, mode::read) == false) return false;
|
||||
if(wr.open(targetname, mode::write) == false) return false;
|
||||
for(uint n = 0; n < rd.size(); n++) wr.write(rd.read());
|
||||
return true;
|
||||
if(auto reader = file::open(sourcename, mode::read)) {
|
||||
if(auto writer = file::open(targetname, mode::write)) {
|
||||
for(uint64_t n : range(reader.size())) writer.write(reader.read());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//attempt to rename file first
|
||||
@ -29,14 +31,11 @@ struct file : inode, varint {
|
||||
if(sourcename == targetname) return true;
|
||||
if(rename(sourcename, targetname)) return true;
|
||||
if(!writable(sourcename)) return false;
|
||||
if(copy(sourcename, targetname)) {
|
||||
remove(sourcename);
|
||||
return true;
|
||||
}
|
||||
if(copy(sourcename, targetname)) return remove(sourcename), true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static auto truncate(const string& filename, uint size) -> bool {
|
||||
static auto truncate(const string& filename, uint64_t size) -> bool {
|
||||
#if defined(API_POSIX)
|
||||
return truncate(filename, size) == 0;
|
||||
#elif defined(API_WINDOWS)
|
||||
@ -61,7 +60,7 @@ struct file : inode, varint {
|
||||
return !(data.st_mode & S_IFDIR);
|
||||
}
|
||||
|
||||
static auto size(const string& filename) -> uintmax {
|
||||
static auto size(const string& filename) -> uint64_t {
|
||||
#if defined(API_POSIX)
|
||||
struct stat data;
|
||||
stat(filename, &data);
|
||||
@ -72,263 +71,33 @@ struct file : inode, varint {
|
||||
return S_ISREG(data.st_mode) ? data.st_size : 0u;
|
||||
}
|
||||
|
||||
static auto read(const string& filename, uint reserve = 0) -> vector<uint8_t> {
|
||||
static auto read(const string& filename) -> vector<uint8_t> {
|
||||
vector<uint8_t> memory;
|
||||
file fp;
|
||||
if(fp.open(filename, mode::read)) {
|
||||
memory.reserve(fp.size() + reserve);
|
||||
if(auto fp = file::open(filename, mode::read)) {
|
||||
memory.resize(fp.size());
|
||||
fp.read(memory.data(), memory.size());
|
||||
fp.read(memory);
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
static auto read(const string& filename, void* data, uint size) -> bool {
|
||||
file fp;
|
||||
if(fp.open(filename, mode::read) == false) return false;
|
||||
fp.read(data, size);
|
||||
fp.close();
|
||||
return true;
|
||||
static auto read(const string& filename, array_span<uint8_t> memory) -> bool {
|
||||
if(auto fp = file::open(filename, mode::read)) return fp.read(memory), true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static auto write(const string& filename, const string& text) -> bool {
|
||||
return write(filename, text.data(), text.size());
|
||||
}
|
||||
|
||||
static auto write(const string& filename, const vector<uint8_t>& buffer) -> bool {
|
||||
return write(filename, buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
static auto write(const string& filename, const void* data, uint size) -> bool {
|
||||
file fp;
|
||||
if(fp.open(filename, mode::write) == false) return false;
|
||||
fp.write(data, size);
|
||||
fp.close();
|
||||
return true;
|
||||
static auto write(const string& filename, array_view<uint8_t> memory) -> bool {
|
||||
if(auto fp = file::open(filename, mode::write)) return fp.write(memory), true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//create an empty file (will replace existing files)
|
||||
static auto create(const string& filename) -> bool {
|
||||
//create an empty file (will replace existing files)
|
||||
file fp;
|
||||
if(fp.open(filename, mode::write) == false) return false;
|
||||
fp.close();
|
||||
return true;
|
||||
if(auto fp = file::open(filename, mode::write)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static auto sha256(const string& filename) -> string {
|
||||
auto buffer = read(filename);
|
||||
return Hash::SHA256(buffer).digest();
|
||||
}
|
||||
|
||||
auto read() -> uint8_t {
|
||||
if(!fp) return 0xff; //file not open
|
||||
if(file_mode == mode::write) return 0xff; //reads not permitted
|
||||
if(file_offset >= file_size) return 0xff; //cannot read past end of file
|
||||
buffer_sync();
|
||||
return buffer[(file_offset++) & buffer_mask];
|
||||
}
|
||||
|
||||
auto readl(uint length = 1) -> uintmax {
|
||||
uintmax data = 0;
|
||||
for(int i = 0; i < length; i++) {
|
||||
data |= (uintmax)read() << (i << 3);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
auto readm(uint length = 1) -> uintmax {
|
||||
uintmax data = 0;
|
||||
while(length--) {
|
||||
data <<= 8;
|
||||
data |= read();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
auto reads(uint length) -> string {
|
||||
string result;
|
||||
result.resize(length);
|
||||
for(auto& byte : result) byte = read();
|
||||
return result;
|
||||
}
|
||||
|
||||
auto read(void* data, uint size) -> void {
|
||||
auto output = (uint8_t*)data;
|
||||
while(size--) *output++ = read();
|
||||
}
|
||||
|
||||
auto write(uint8_t data) -> void {
|
||||
if(!fp) return; //file not open
|
||||
if(file_mode == mode::read) return; //writes not permitted
|
||||
buffer_sync();
|
||||
buffer[(file_offset++) & buffer_mask] = data;
|
||||
buffer_dirty = true;
|
||||
if(file_offset > file_size) file_size = file_offset;
|
||||
}
|
||||
|
||||
auto writel(uintmax data, uint length = 1) -> void {
|
||||
while(length--) {
|
||||
write(data);
|
||||
data >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
auto writem(uintmax data, uint length = 1) -> void {
|
||||
for(int i = length - 1; i >= 0; i--) {
|
||||
write(data >> (i << 3));
|
||||
}
|
||||
}
|
||||
|
||||
auto writes(const string& s) -> void {
|
||||
for(auto byte : s) write(byte);
|
||||
}
|
||||
|
||||
auto write(const void* data, uint size) -> void {
|
||||
auto input = (const uint8_t*)data;
|
||||
while(size--) write(*input++);
|
||||
}
|
||||
|
||||
template<typename... Args> auto print(Args... args) -> void {
|
||||
string data(args...);
|
||||
const char* p = data;
|
||||
while(*p) write(*p++);
|
||||
}
|
||||
|
||||
auto flush() -> void {
|
||||
buffer_flush();
|
||||
fflush(fp);
|
||||
}
|
||||
|
||||
auto seek(int offset, index index_ = index::absolute) -> void {
|
||||
if(!fp) return; //file not open
|
||||
buffer_flush();
|
||||
|
||||
intmax req_offset = file_offset;
|
||||
switch(index_) {
|
||||
case index::absolute: req_offset = offset; break;
|
||||
case index::relative: req_offset += offset; break;
|
||||
}
|
||||
|
||||
if(req_offset < 0) req_offset = 0; //cannot seek before start of file
|
||||
if(req_offset > file_size) {
|
||||
if(file_mode == mode::read) { //cannot seek past end of file
|
||||
req_offset = file_size;
|
||||
} else { //pad file to requested location
|
||||
file_offset = file_size;
|
||||
while(file_size < req_offset) write(0x00);
|
||||
}
|
||||
}
|
||||
|
||||
file_offset = req_offset;
|
||||
}
|
||||
|
||||
auto offset() const -> uint {
|
||||
if(!fp) return 0; //file not open
|
||||
return file_offset;
|
||||
}
|
||||
|
||||
auto size() const -> uint {
|
||||
if(!fp) return 0; //file not open
|
||||
return file_size;
|
||||
}
|
||||
|
||||
auto truncate(uint size) -> bool {
|
||||
if(!fp) return false; //file not open
|
||||
#if defined(API_POSIX)
|
||||
return ftruncate(fileno(fp), size) == 0;
|
||||
#elif defined(API_WINDOWS)
|
||||
return _chsize(fileno(fp), size) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
auto end() const -> bool {
|
||||
if(!fp) return true; //file not open
|
||||
return file_offset >= file_size;
|
||||
}
|
||||
|
||||
auto open() const -> bool {
|
||||
return fp;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return open();
|
||||
}
|
||||
|
||||
auto open(const string& filename, mode mode_) -> bool {
|
||||
if(fp) return false;
|
||||
|
||||
switch(file_mode = mode_) {
|
||||
#if defined(API_POSIX)
|
||||
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;
|
||||
#elif defined(API_WINDOWS)
|
||||
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;
|
||||
buffer_offset = -1; //invalidate buffer
|
||||
file_offset = 0;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
file_size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto close() -> void {
|
||||
if(!fp) return;
|
||||
buffer_flush();
|
||||
fclose(fp);
|
||||
fp = nullptr;
|
||||
}
|
||||
|
||||
auto operator=(const file&) -> file& = delete;
|
||||
file(const file&) = delete;
|
||||
file() = default;
|
||||
|
||||
file(const string& filename, mode mode_) {
|
||||
open(filename, mode_);
|
||||
}
|
||||
|
||||
~file() {
|
||||
close();
|
||||
}
|
||||
|
||||
private:
|
||||
enum { buffer_size = 1 << 12, buffer_mask = buffer_size - 1 };
|
||||
char buffer[buffer_size] = {0};
|
||||
int buffer_offset = -1; //invalidate buffer
|
||||
bool buffer_dirty = false;
|
||||
FILE* fp = nullptr;
|
||||
uint file_offset = 0;
|
||||
uint file_size = 0;
|
||||
mode file_mode = mode::read;
|
||||
|
||||
auto buffer_sync() -> void {
|
||||
if(!fp) return; //file not open
|
||||
if(buffer_offset != (file_offset & ~buffer_mask)) {
|
||||
buffer_flush();
|
||||
buffer_offset = file_offset & ~buffer_mask;
|
||||
fseek(fp, buffer_offset, SEEK_SET);
|
||||
uint length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
|
||||
if(length) auto unused = fread(buffer, 1, length, fp);
|
||||
}
|
||||
}
|
||||
|
||||
auto buffer_flush() -> void {
|
||||
if(!fp) return; //file not open
|
||||
if(file_mode == mode::read) return; //buffer cannot be written to
|
||||
if(buffer_offset < 0) return; //buffer unused
|
||||
if(buffer_dirty == false) return; //buffer unmodified since read
|
||||
fseek(fp, buffer_offset, SEEK_SET);
|
||||
uint length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
|
||||
if(length) auto unused = fwrite(buffer, 1, length, fp);
|
||||
buffer_offset = -1; //invalidate buffer
|
||||
buffer_dirty = false;
|
||||
return Hash::SHA256(read(filename)).digest();
|
||||
}
|
||||
};
|
||||
|
||||
|
213
nall/filemap.hpp
213
nall/filemap.hpp
@ -1,213 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
#include <nall/windows/utf8.hpp>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct filemap {
|
||||
enum class mode : unsigned { read, write, readwrite, writeread };
|
||||
|
||||
filemap() { p_ctor(); }
|
||||
filemap(const string& filename, mode mode_) { p_ctor(); p_open(filename, mode_); }
|
||||
~filemap() { p_dtor(); }
|
||||
|
||||
explicit operator bool() const { return open(); }
|
||||
auto open() const -> bool { return p_open(); }
|
||||
auto open(const string& filename, mode mode_) -> bool { return p_open(filename, mode_); }
|
||||
auto close() -> void { return p_close(); }
|
||||
auto size() const -> unsigned { return p_size; }
|
||||
auto data() -> uint8_t* { return p_handle; }
|
||||
auto data() const -> const uint8_t* { return p_handle; }
|
||||
|
||||
private:
|
||||
uint8_t* p_handle = nullptr;
|
||||
unsigned p_size = 0;
|
||||
|
||||
#if defined(API_WINDOWS)
|
||||
//=============
|
||||
//MapViewOfFile
|
||||
//=============
|
||||
|
||||
HANDLE p_filehandle;
|
||||
HANDLE p_maphandle;
|
||||
|
||||
auto p_open() const -> bool {
|
||||
return p_handle;
|
||||
}
|
||||
|
||||
auto p_open(const string& filename, mode mode_) -> bool {
|
||||
if(file::exists(filename) && file::size(filename) == 0) {
|
||||
p_handle = nullptr;
|
||||
p_size = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int desired_access, creation_disposition, flprotect, map_access;
|
||||
|
||||
switch(mode_) {
|
||||
default: return false;
|
||||
case mode::read:
|
||||
desired_access = GENERIC_READ;
|
||||
creation_disposition = OPEN_EXISTING;
|
||||
flprotect = PAGE_READONLY;
|
||||
map_access = FILE_MAP_READ;
|
||||
break;
|
||||
case mode::write:
|
||||
//write access requires read access
|
||||
desired_access = GENERIC_WRITE;
|
||||
creation_disposition = CREATE_ALWAYS;
|
||||
flprotect = PAGE_READWRITE;
|
||||
map_access = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
case mode::readwrite:
|
||||
desired_access = GENERIC_READ | GENERIC_WRITE;
|
||||
creation_disposition = OPEN_EXISTING;
|
||||
flprotect = PAGE_READWRITE;
|
||||
map_access = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
case mode::writeread:
|
||||
desired_access = GENERIC_READ | GENERIC_WRITE;
|
||||
creation_disposition = CREATE_NEW;
|
||||
flprotect = PAGE_READWRITE;
|
||||
map_access = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
p_filehandle = CreateFileW(utf16_t(filename), desired_access, FILE_SHARE_READ, nullptr,
|
||||
creation_disposition, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if(p_filehandle == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
p_size = GetFileSize(p_filehandle, nullptr);
|
||||
|
||||
p_maphandle = CreateFileMapping(p_filehandle, nullptr, flprotect, 0, p_size, nullptr);
|
||||
if(p_maphandle == INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(p_filehandle);
|
||||
p_filehandle = INVALID_HANDLE_VALUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
p_handle = (uint8_t*)MapViewOfFile(p_maphandle, map_access, 0, 0, p_size);
|
||||
return p_handle;
|
||||
}
|
||||
|
||||
auto p_close() -> void {
|
||||
if(p_handle) {
|
||||
UnmapViewOfFile(p_handle);
|
||||
p_handle = nullptr;
|
||||
}
|
||||
|
||||
if(p_maphandle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(p_maphandle);
|
||||
p_maphandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if(p_filehandle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(p_filehandle);
|
||||
p_filehandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
auto p_ctor() -> void {
|
||||
p_filehandle = INVALID_HANDLE_VALUE;
|
||||
p_maphandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
auto p_dtor() -> void {
|
||||
close();
|
||||
}
|
||||
|
||||
#else
|
||||
//====
|
||||
//mmap
|
||||
//====
|
||||
|
||||
int p_fd;
|
||||
|
||||
auto p_open() const -> bool {
|
||||
return p_handle;
|
||||
}
|
||||
|
||||
auto p_open(const string& filename, mode mode_) -> bool {
|
||||
if(file::exists(filename) && file::size(filename) == 0) {
|
||||
p_handle = nullptr;
|
||||
p_size = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int open_flags, mmap_flags;
|
||||
|
||||
switch(mode_) {
|
||||
default: return false;
|
||||
case mode::read:
|
||||
open_flags = O_RDONLY;
|
||||
mmap_flags = PROT_READ;
|
||||
break;
|
||||
case mode::write:
|
||||
open_flags = O_RDWR | O_CREAT; //mmap() requires read access
|
||||
mmap_flags = PROT_WRITE;
|
||||
break;
|
||||
case mode::readwrite:
|
||||
open_flags = O_RDWR;
|
||||
mmap_flags = PROT_READ | PROT_WRITE;
|
||||
break;
|
||||
case mode::writeread:
|
||||
open_flags = O_RDWR | O_CREAT;
|
||||
mmap_flags = PROT_READ | PROT_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
p_fd = ::open(filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
if(p_fd < 0) return false;
|
||||
|
||||
struct stat p_stat;
|
||||
fstat(p_fd, &p_stat);
|
||||
p_size = p_stat.st_size;
|
||||
|
||||
p_handle = (uint8_t*)mmap(nullptr, p_size, mmap_flags, MAP_SHARED, p_fd, 0);
|
||||
if(p_handle == MAP_FAILED) {
|
||||
p_handle = nullptr;
|
||||
::close(p_fd);
|
||||
p_fd = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_handle;
|
||||
}
|
||||
|
||||
auto p_close() -> void {
|
||||
if(p_handle) {
|
||||
munmap(p_handle, p_size);
|
||||
p_handle = nullptr;
|
||||
}
|
||||
|
||||
if(p_fd >= 0) {
|
||||
::close(p_fd);
|
||||
p_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto p_ctor() -> void {
|
||||
p_fd = -1;
|
||||
}
|
||||
|
||||
auto p_dtor() -> void {
|
||||
p_close();
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/file-map.hpp>
|
||||
#include <nall/interpolation.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/decode/bmp.hpp>
|
||||
|
@ -11,6 +11,10 @@ namespace nall {
|
||||
struct inode {
|
||||
enum class time : uint { create, modify, access };
|
||||
|
||||
inode() = delete;
|
||||
inode(const inode&) = delete;
|
||||
auto operator=(const inode&) -> inode& = delete;
|
||||
|
||||
static auto exists(const string& name) -> bool {
|
||||
return access(name, F_OK) == 0;
|
||||
}
|
||||
@ -45,19 +49,21 @@ struct inode {
|
||||
return data.st_gid;
|
||||
}
|
||||
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
static auto user(const string& name) -> string {
|
||||
static auto owner(const string& name) -> string {
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
struct passwd* pw = getpwuid(uid(name));
|
||||
if(pw && pw->pw_name) return pw->pw_name;
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
static auto group(const string& name) -> string {
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
struct group* gr = getgrgid(gid(name));
|
||||
if(gr && gr->gr_name) return gr->gr_name;
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
static auto timestamp(const string& name, time mode = time::modify) -> uint64_t {
|
||||
struct stat data{};
|
||||
@ -83,6 +89,41 @@ struct inode {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static auto setMode(const string& name, uint mode) -> bool {
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
return chmod(name, mode) == 0;
|
||||
#else
|
||||
return _wchmod(utf16_t(name), (mode & 0400 ? _S_IREAD : 0) | (mode & 0200 ? _S_IWRITE : 0)) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static auto setOwner(const string& name, const string& owner) -> bool {
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
struct passwd* pwd = getpwnam(owner);
|
||||
if(!pwd) return false;
|
||||
return chown(name, pwd->pw_uid, inode::gid(name)) == 0;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static auto setGroup(const string& name, const string& group) -> bool {
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
struct group* grp = getgrnam(group);
|
||||
if(!grp) return false;
|
||||
return chown(name, inode::uid(name), grp->gr_gid) == 0;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static auto setTimestamp(const string& name, uint64_t value, time mode = time::modify) -> bool {
|
||||
struct utimbuf timeBuffer;
|
||||
timeBuffer.modtime = mode == time::modify ? value : inode::timestamp(name, time::modify);
|
||||
timeBuffer.actime = mode == time::access ? value : inode::timestamp(name, time::access);
|
||||
return utime(name, &timeBuffer) == 0;
|
||||
}
|
||||
|
||||
//returns true if 'name' already exists
|
||||
static auto create(const string& name, uint permissions = 0755) -> bool {
|
||||
if(exists(name)) return true;
|
||||
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
//note: gcc 4.9 does not support user-defined literals with arguments other than const char*
|
||||
//once nall increases the minimum required GCC version, the use of nall/atoi.hpp can beremoved
|
||||
|
||||
#include <nall/atoi.hpp>
|
||||
|
||||
namespace nall { namespace Literal {
|
||||
|
||||
struct Capacity { uint value; };
|
||||
struct Size { uint value; };
|
||||
|
||||
}}
|
||||
|
||||
namespace nall {
|
||||
|
||||
constexpr inline auto operator"" _capacity(const char* s) -> Literal::Capacity {
|
||||
return {(uint)toNatural(s)};
|
||||
}
|
||||
|
||||
constexpr inline auto operator"" _size(const char* s) -> Literal::Size {
|
||||
return {(uint)toNatural(s)};
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/string.hpp>
|
||||
|
||||
namespace nall { namespace Location {
|
||||
|
||||
// (/parent/child.type/)
|
||||
|
@ -5,6 +5,12 @@
|
||||
namespace nall { namespace MAC {
|
||||
|
||||
struct Poly1305 {
|
||||
auto authenticate(array_view<uint8_t> memory, uint256_t nonce) -> uint128_t {
|
||||
initialize(nonce);
|
||||
process(memory.data(), memory.size());
|
||||
return finish();
|
||||
}
|
||||
|
||||
auto initialize(uint256_t key) -> void {
|
||||
uint64_t t0 = key >> 0;
|
||||
uint64_t t1 = key >> 64;
|
||||
|
@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/arguments.hpp>
|
||||
#include <nall/string.hpp>
|
||||
|
||||
namespace nall {
|
||||
auto main(vector<string> arguments) -> void;
|
||||
auto main(Arguments arguments) -> void;
|
||||
|
||||
auto main(int argc, char** argv) -> int {
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
@ -14,21 +15,8 @@ namespace nall {
|
||||
_setmode(_fileno(stdin), O_BINARY);
|
||||
_setmode(_fileno(stdout), O_BINARY);
|
||||
_setmode(_fileno(stderr), O_BINARY);
|
||||
utf8_arguments(argc, argv);
|
||||
#endif
|
||||
|
||||
vector<string> arguments;
|
||||
for(auto n : range(argc)) {
|
||||
string argument = argv[n];
|
||||
|
||||
//normalize directory and file path arguments
|
||||
if(directory::exists(argument)) argument.transform("\\", "/").trimRight("/").append("/");
|
||||
else if(file::exists(argument)) argument.transform("\\", "/").trimRight("/");
|
||||
|
||||
arguments.append(argument);
|
||||
}
|
||||
|
||||
return main(move(arguments)), EXIT_SUCCESS;
|
||||
return main(move(Arguments{argc, argv})), EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/any.hpp>
|
||||
//#include <nall/arguments.hpp>
|
||||
#include <nall/arithmetic.hpp>
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/array-span.hpp>
|
||||
@ -28,7 +29,8 @@
|
||||
#include <nall/dl.hpp>
|
||||
#include <nall/endian.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/file-buffer.hpp>
|
||||
#include <nall/file-map.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/hashset.hpp>
|
||||
#include <nall/hid.hpp>
|
||||
@ -58,6 +60,7 @@
|
||||
#include <nall/simd.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/terminal.hpp>
|
||||
#include <nall/thread.hpp>
|
||||
#include <nall/traits.hpp>
|
||||
#include <nall/unique-pointer.hpp>
|
||||
@ -65,6 +68,7 @@
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/view.hpp>
|
||||
#include <nall/arguments.hpp> //todo: compilation errors when included earlier
|
||||
#include <nall/decode/base.hpp>
|
||||
#include <nall/decode/base64.hpp>
|
||||
#include <nall/decode/bmp.hpp>
|
||||
|
@ -6,7 +6,7 @@ namespace nall { namespace Path {
|
||||
|
||||
inline auto active() -> string {
|
||||
char path[PATH_MAX] = "";
|
||||
auto unused = getcwd(path, PATH_MAX);
|
||||
(void)getcwd(path, PATH_MAX);
|
||||
string result = path;
|
||||
if(!result) result = ".";
|
||||
result.transform("\\", "/");
|
||||
|
@ -37,6 +37,7 @@ namespace Math {
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <utime.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -54,8 +54,10 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
namespace PRNG {
|
||||
|
||||
//Galois linear feedback shift register using CRC64 polynomials
|
||||
struct PRNG_LFSR : RNG<PRNG_LFSR> {
|
||||
struct LFSR : RNG<LFSR> {
|
||||
auto seed(maybe<uint64_t> seed = {}) -> void {
|
||||
lfsr = seed ? seed() : (uint64_t)randomSeed();
|
||||
for(uint n : range(8)) read(); //hide the CRC64 polynomial from initial output
|
||||
@ -73,10 +75,10 @@ private:
|
||||
static const uint64_t crc64 = 0xc96c'5795'd787'0f42;
|
||||
uint64_t lfsr = crc64;
|
||||
|
||||
friend class RNG<PRNG_LFSR>;
|
||||
friend class RNG<LFSR>;
|
||||
};
|
||||
|
||||
struct PRNG_PCG : RNG<PRNG_PCG> {
|
||||
struct PCG : RNG<PCG> {
|
||||
auto seed(maybe<uint32_t> seed = {}, maybe<uint32_t> sequence = {}) -> void {
|
||||
if(!seed) seed = (uint32_t)randomSeed();
|
||||
if(!sequence) sequence = 0;
|
||||
@ -105,12 +107,16 @@ private:
|
||||
uint64_t state = 0;
|
||||
uint64_t increment = 0;
|
||||
|
||||
friend class RNG<PRNG_PCG>;
|
||||
friend class RNG<PCG>;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace CSPRNG {
|
||||
|
||||
//XChaCha20 cryptographically secure pseudo-random number generator
|
||||
struct CSPRNG_XChaCha20 : RNG<CSPRNG_XChaCha20> {
|
||||
CSPRNG_XChaCha20() { seed(); }
|
||||
struct XChaCha20 : RNG<XChaCha20> {
|
||||
XChaCha20() { seed(); }
|
||||
|
||||
auto seed(maybe<uint256_t> key = {}, maybe<uint192_t> nonce = {}) -> void {
|
||||
//the randomness comes from the key; the nonce just adds a bit of added entropy
|
||||
@ -130,16 +136,15 @@ private:
|
||||
Cipher::XChaCha20 context{0, 0};
|
||||
uint counter = 0;
|
||||
|
||||
friend class RNG<CSPRNG_XChaCha20>;
|
||||
friend class RNG<XChaCha20>;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
using PRNG = PRNG_PCG;
|
||||
using CSPRNG = CSPRNG_XChaCha20;
|
||||
|
||||
template<typename T = uint64_t> inline auto random() -> T {
|
||||
static PRNG_PCG pcg; //note: unseeded
|
||||
static PRNG::PCG pcg; //note: unseeded
|
||||
return pcg.random<T>();
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,10 @@ struct has_serialize {
|
||||
struct serializer {
|
||||
enum Mode : uint { Load, Save, Size };
|
||||
|
||||
explicit operator bool() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
auto mode() const -> Mode {
|
||||
return _mode;
|
||||
}
|
||||
|
@ -234,6 +234,20 @@ template<> struct stringify<const string_view&> {
|
||||
const string_view& _view;
|
||||
};
|
||||
|
||||
template<> struct stringify<array_view<uint8_t>> {
|
||||
stringify(const array_view<uint8_t>& source) : _view(source) {}
|
||||
auto data() const -> const char* { return _view.data<const char>(); }
|
||||
auto size() const -> uint { return _view.size(); }
|
||||
const array_view<uint8_t>& _view;
|
||||
};
|
||||
|
||||
template<> struct stringify<const array_view<uint8_t>&> {
|
||||
stringify(const array_view<uint8_t>& source) : _view(source) {}
|
||||
auto data() const -> const char* { return _view.data<const char>(); }
|
||||
auto size() const -> uint { return _view.size(); }
|
||||
const array_view<uint8_t>& _view;
|
||||
};
|
||||
|
||||
template<> struct stringify<string_pascal> {
|
||||
stringify(const string_pascal& source) : _text(source) {}
|
||||
auto data() const -> const char* { return _text.data(); }
|
||||
@ -250,6 +264,7 @@ template<> struct stringify<const string_pascal&> {
|
||||
|
||||
//pointers
|
||||
|
||||
//note: T = char* is matched by stringify<string_view>
|
||||
template<typename T> struct stringify<T*> {
|
||||
stringify(const T* source) {
|
||||
if(!source) {
|
||||
|
@ -18,7 +18,7 @@ auto string::read(string_view filename) -> string {
|
||||
|
||||
rewind(fp);
|
||||
result.resize(filesize);
|
||||
auto unused = fread(result.get(), 1, filesize, fp);
|
||||
(void)fread(result.get(), 1, filesize, fp);
|
||||
return fclose(fp), result;
|
||||
}
|
||||
|
||||
|
65
nall/terminal.hpp
Normal file
65
nall/terminal.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/string.hpp>
|
||||
|
||||
namespace nall { namespace terminal {
|
||||
|
||||
inline auto escapable() -> bool {
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
//todo: colors are supported by Windows 10+ and with alternate terminals (eg msys)
|
||||
//disabled for now for compatibility with Windows 7 and 8.1's cmd.exe
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace color {
|
||||
|
||||
template<typename... P> inline auto black(P&&... p) -> string {
|
||||
if(!escapable()) return string{forward<P>(p)...};
|
||||
return {"\e[30m", string{forward<P>(p)...}, "\e[0m"};
|
||||
}
|
||||
|
||||
template<typename... P> inline auto blue(P&&... p) -> string {
|
||||
if(!escapable()) return string{forward<P>(p)...};
|
||||
return {"\e[94m", string{forward<P>(p)...}, "\e[0m"};
|
||||
}
|
||||
|
||||
template<typename... P> inline auto green(P&&... p) -> string {
|
||||
if(!escapable()) return string{forward<P>(p)...};
|
||||
return {"\e[92m", string{forward<P>(p)...}, "\e[0m"};
|
||||
}
|
||||
|
||||
template<typename... P> inline auto cyan(P&&... p) -> string {
|
||||
if(!escapable()) return string{forward<P>(p)...};
|
||||
return {"\e[96m", string{forward<P>(p)...}, "\e[0m"};
|
||||
}
|
||||
|
||||
template<typename... P> inline auto red(P&&... p) -> string {
|
||||
if(!escapable()) return string{forward<P>(p)...};
|
||||
return {"\e[91m", string{forward<P>(p)...}, "\e[0m"};
|
||||
}
|
||||
|
||||
template<typename... P> inline auto magenta(P&&... p) -> string {
|
||||
if(!escapable()) return string{forward<P>(p)...};
|
||||
return {"\e[95m", string{forward<P>(p)...}, "\e[0m"};
|
||||
}
|
||||
|
||||
template<typename... P> inline auto yellow(P&&... p) -> string {
|
||||
if(!escapable()) return string{forward<P>(p)...};
|
||||
return {"\e[93m", string{forward<P>(p)...}, "\e[0m"};
|
||||
}
|
||||
|
||||
template<typename... P> inline auto white(P&&... p) -> string {
|
||||
if(!escapable()) return string{forward<P>(p)...};
|
||||
return {"\e[97m", string{forward<P>(p)...}, "\e[0m"};
|
||||
}
|
||||
|
||||
template<typename... P> inline auto gray(P&&... p) -> string {
|
||||
if(!escapable()) return string{forward<P>(p)...};
|
||||
return {"\e[37m", string{forward<P>(p)...}, "\e[0m"};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}}
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
//pull all type traits used by nall from std namespace into nall namespace
|
||||
//this removes the requirement to prefix type traits with std:: within nall
|
||||
@ -29,3 +30,10 @@ namespace nall {
|
||||
using std::swap;
|
||||
using std::true_type;
|
||||
}
|
||||
|
||||
namespace std {
|
||||
#if INTMAX_BITS >= 128
|
||||
template<> struct is_signed<int128_t> : true_type {};
|
||||
template<> struct is_unsigned<uint128_t> : true_type {};
|
||||
#endif
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <nall/bit.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/iterator.hpp>
|
||||
#include <nall/literals.hpp>
|
||||
#include <nall/maybe.hpp>
|
||||
#include <nall/memory.hpp>
|
||||
#include <nall/merge-sort.hpp>
|
||||
@ -23,8 +22,6 @@ struct vector_base {
|
||||
|
||||
//core.hpp
|
||||
vector_base() = default;
|
||||
vector_base(Literal::Capacity capacity);
|
||||
vector_base(Literal::Size size);
|
||||
vector_base(const initializer_list<T>& values);
|
||||
vector_base(const type& source);
|
||||
vector_base(type&& source);
|
||||
@ -121,6 +118,7 @@ struct vector_base {
|
||||
//utility.hpp
|
||||
auto fill(const T& value = {}) -> void;
|
||||
auto sort(const function<bool (const T& lhs, const T& rhs)>& comparator = [](auto& lhs, auto& rhs) { return lhs < rhs; }) -> void;
|
||||
auto reverse() -> void;
|
||||
auto find(const function<bool (const T& lhs)>& comparator) -> maybe<uint>;
|
||||
auto find(const T& value) const -> maybe<uint>;
|
||||
auto findSorted(const T& value) const -> maybe<uint>;
|
||||
|
@ -2,14 +2,6 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename T> vector<T>::vector(Literal::Capacity capacity) {
|
||||
reserve(capacity.value);
|
||||
}
|
||||
|
||||
template<typename T> vector<T>::vector(Literal::Size size) {
|
||||
resize(size.value);
|
||||
}
|
||||
|
||||
template<typename T> vector<T>::vector(const initializer_list<T>& values) {
|
||||
reserveRight(values.size());
|
||||
for(auto& value : values) append(value);
|
||||
|
@ -119,7 +119,7 @@ template<typename T> auto vector<T>::resizeLeft(uint size, const T& value) -> bo
|
||||
if(size > _size) { //grow
|
||||
reserveLeft(size);
|
||||
_pool -= size - _size;
|
||||
for(uint n : reverse(range(size - _size))) new(_pool + n) T(value);
|
||||
for(uint n : nall::reverse(range(size - _size))) new(_pool + n) T(value);
|
||||
_left -= size - _size;
|
||||
_size = size;
|
||||
return true;
|
||||
|
@ -11,7 +11,27 @@ template<> struct vector<uint8_t> : vector_base<uint8_t> {
|
||||
}
|
||||
|
||||
template<typename U> auto appendm(U value, uint size) -> void {
|
||||
for(uint byte : reverse(range(size))) append(uint8_t(value >> byte * 8));
|
||||
for(uint byte : nall::reverse(range(size))) append(uint8_t(value >> byte * 8));
|
||||
}
|
||||
|
||||
//note: string_view is not declared here yet ...
|
||||
auto appends(array_view<uint8_t> memory) -> void {
|
||||
for(uint8_t byte : memory) append(byte);
|
||||
}
|
||||
|
||||
template<typename U> auto readl(int offset, uint size) -> U {
|
||||
if(offset < 0) offset = this->size() - abs(offset);
|
||||
U value = 0;
|
||||
for(uint byte : range(size)) value |= (U)operator[](offset + byte) << byte * 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
auto view(uint offset, uint length) -> array_view<uint8_t> {
|
||||
#ifdef DEBUG
|
||||
struct out_of_bounds {};
|
||||
if(offset + length >= size()) throw out_of_bounds{};
|
||||
#endif
|
||||
return {data() + offset, length};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,12 @@ template<typename T> auto vector<T>::sort(const function<bool (const T& lhs, con
|
||||
nall::sort(_pool, _size, comparator);
|
||||
}
|
||||
|
||||
template<typename T> auto vector<T>::reverse() -> void {
|
||||
vector<T> reversed;
|
||||
for(uint n : range(size())) reversed.prepend(_pool[n]);
|
||||
operator=(move(reversed));
|
||||
}
|
||||
|
||||
template<typename T> auto vector<T>::find(const function<bool (const T& lhs)>& comparator) -> maybe<uint> {
|
||||
for(uint n : range(size())) if(comparator(_pool[n])) return n;
|
||||
return nothing;
|
||||
|
@ -20,7 +20,7 @@ struct file : vfs::file {
|
||||
}
|
||||
|
||||
auto seek(intmax offset_, index index_) -> void override {
|
||||
_fp.seek(offset_, (nall::file::index)index_);
|
||||
_fp.seek(offset_, (uint)index_);
|
||||
}
|
||||
|
||||
auto read() -> uint8_t override {
|
||||
@ -41,11 +41,11 @@ private:
|
||||
auto operator=(const file&) -> file& = delete;
|
||||
|
||||
auto _open(string location_, mode mode_) -> bool {
|
||||
if(!_fp.open(location_, (nall::file::mode)mode_)) return false;
|
||||
if(!_fp.open(location_, (uint)mode_)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
nall::file _fp;
|
||||
file_buffer _fp;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
@ -123,7 +123,7 @@ struct InputJoypadUdev {
|
||||
play.type = EV_FF;
|
||||
play.code = jp.effectID;
|
||||
play.value = enable;
|
||||
auto unused = write(jp.fd, &play, sizeof(input_event));
|
||||
(void)write(jp.fd, &play, sizeof(input_event));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user