├── beat ├── .gitignore ├── archive │ ├── extract.hpp │ └── create.hpp └── single │ └── apply.hpp ├── recompiler ├── .gitignore └── amd64 │ ├── amd64.hpp │ └── emitter.hpp ├── vfs.hpp ├── dsp ├── dsp.hpp ├── iir │ ├── dc-removal.hpp │ └── one-pole.hpp └── resampler │ └── cubic.hpp ├── view.hpp ├── shared-memory.hpp ├── macos └── guard.hpp ├── service.hpp ├── xorg ├── clipboard.hpp ├── xorg.hpp └── guard.hpp ├── windows ├── guid.hpp ├── service.hpp ├── guard.hpp ├── shared-memory.hpp └── utf8.hpp ├── cd ├── crc16.hpp ├── sync.hpp ├── scrambler.hpp ├── edc.hpp └── efm.hpp ├── vector ├── compare.hpp ├── assign.hpp ├── specialization │ └── uint8_t.hpp ├── access.hpp ├── core.hpp ├── utility.hpp └── iterator.hpp ├── string ├── atoi.hpp ├── utf8.hpp ├── eval │ ├── node.hpp │ └── literal.hpp ├── convert.hpp ├── split.hpp ├── vector.hpp ├── allocator │ ├── vector.hpp │ ├── copy-on-write.hpp │ └── small-string-optimization.hpp ├── view.hpp ├── match.hpp ├── compare.hpp ├── pascal.hpp ├── core.hpp └── find.hpp ├── encode ├── html.hpp ├── mtf.hpp ├── url.hpp ├── wav.hpp ├── base.hpp ├── rle.hpp ├── bmp.hpp ├── base64.hpp ├── huffman.hpp ├── lzsa.hpp └── bwt.hpp ├── decode ├── mtf.hpp ├── huffman.hpp ├── bwt.hpp ├── rle.hpp ├── base64.hpp ├── html.hpp ├── base.hpp ├── url.hpp ├── gzip.hpp ├── lzsa.hpp ├── bmp.hpp └── wav.hpp ├── inline-if.hpp ├── property.hpp ├── counting-sort.hpp ├── instance.hpp ├── algorithm.hpp ├── utility.hpp ├── arithmetic ├── barrett.hpp └── unsigned.hpp ├── image ├── static.hpp ├── interpolation.hpp ├── blend.hpp ├── load.hpp └── fill.hpp ├── primitives.hpp ├── matrix-multiply.hpp ├── pointer.hpp ├── cd.hpp ├── primitives ├── boolean.hpp ├── real.hpp └── bit-field.hpp ├── vfs ├── disk.hpp ├── vfs.hpp └── memory.hpp ├── hash ├── crc32.hpp ├── crc16.hpp ├── crc64.hpp └── hash.hpp ├── literals.hpp ├── traits.hpp ├── http └── client.hpp ├── adaptive-array.hpp ├── main.hpp ├── elliptic-curve ├── curve25519.hpp └── modulo25519-reference.hpp ├── range.hpp ├── interpolation.hpp ├── endian.hpp ├── terminal.hpp ├── stdint.hpp ├── galois-field.hpp ├── map.hpp ├── array.hpp ├── arithmetic.hpp ├── bump-allocator.hpp ├── atoi.hpp ├── locale.hpp ├── merge-sort.hpp ├── any.hpp ├── bit.hpp ├── location.hpp ├── nall.hpp ├── array-span.hpp ├── iterator.hpp ├── unique-pointer.hpp ├── queue.hpp └── function.hpp /beat/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recompiler/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vfs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | -------------------------------------------------------------------------------- /dsp/dsp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::DSP { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /view.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template struct view; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /shared-memory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #if defined(API_POSIX) 7 | #include 8 | #endif 9 | 10 | #if defined(API_WINDOWS) 11 | #include 12 | #endif 13 | -------------------------------------------------------------------------------- /macos/guard.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NALL_MACOS_GUARD_HPP 2 | #define NALL_MACOS_GUARD_HPP 3 | 4 | #define Boolean CocoaBoolean 5 | #define decimal CocoaDecimal 6 | #define DEBUG CocoaDebug 7 | 8 | #else 9 | #undef NALL_MACOS_GUARD_HPP 10 | 11 | #undef Boolean 12 | #undef decimal 13 | #undef DEBUG 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /service.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //service model template built on top of shared-memory 4 | 5 | #include 6 | 7 | #if defined(API_POSIX) 8 | #include 9 | #endif 10 | 11 | #if defined(API_WINDOWS) 12 | #include 13 | #endif 14 | -------------------------------------------------------------------------------- /xorg/clipboard.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall::Clipboard { 6 | 7 | inline auto clear() -> void { 8 | XDisplay display; 9 | XlibAtom atom = XInternAtom(display, "CLIPBOARD", XlibFalse); 10 | XSetSelectionOwner(display, atom, XlibNone, XlibCurrentTime); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /windows/guid.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall { 6 | 7 | inline auto guid() -> string { 8 | GUID guidInstance; 9 | CoCreateGuid(&guidInstance); 10 | 11 | wchar_t guidString[39]; 12 | StringFromGUID2(guidInstance, guidString, 39); 13 | 14 | return (char*)utf8_t(guidString); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /cd/crc16.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //CRC-16/KERMIT 4 | 5 | namespace nall::CD { 6 | 7 | inline auto CRC16(array_view data) -> uint16_t { 8 | uint16_t crc = 0; 9 | while(data) { 10 | crc ^= *data++ << 8; 11 | for(uint bit : range(8)) { 12 | crc = crc << 1 ^ (crc & 0x8000 ? 0x1021 : 0); 13 | } 14 | } 15 | return ~crc; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /recompiler/amd64/amd64.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::recompiler { 4 | using u8 = uint8_t; 5 | using u16 = uint16_t; 6 | using u32 = uint32_t; 7 | using u64 = uint64_t; 8 | 9 | struct amd64 { 10 | #include "emitter.hpp" 11 | #include "constants.hpp" 12 | #include "encoder-instructions.hpp" 13 | #include "encoder-calls.hpp" 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /windows/service.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | struct service { 6 | explicit operator bool() const { return false; } 7 | auto command(const string& name, const string& command) -> bool { return false; } 8 | auto receive() -> string { return ""; } 9 | auto name() const -> string { return ""; } 10 | auto stop() const -> bool { return false; } 11 | }; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /xorg/xorg.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct XDisplay { 12 | XDisplay() { _display = XOpenDisplay(nullptr); } 13 | ~XDisplay() { XCloseDisplay(_display); } 14 | operator XlibDisplay*() const { return _display; } 15 | 16 | private: 17 | XlibDisplay* _display; 18 | }; 19 | -------------------------------------------------------------------------------- /vector/compare.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template auto vector::operator==(const vector& source) const -> bool { 6 | if(this == &source) return true; 7 | if(size() != source.size()) return false; 8 | for(uint64_t n = 0; n < size(); n++) { 9 | if(operator[](n) != source[n]) return false; 10 | } 11 | return true; 12 | } 13 | 14 | template auto vector::operator!=(const vector& source) const -> bool { 15 | return !operator==(source); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /string/atoi.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline auto string::boolean() const -> bool { 6 | return equals("true"); 7 | } 8 | 9 | inline auto string::integer() const -> intmax { 10 | return toInteger(data()); 11 | } 12 | 13 | inline auto string::natural() const -> uintmax { 14 | return toNatural(data()); 15 | } 16 | 17 | inline auto string::hex() const -> uintmax { 18 | return toHex(data()); 19 | } 20 | 21 | inline auto string::real() const -> double { 22 | return toReal(data()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /encode/html.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Encode { 4 | 5 | inline auto HTML(const string& input) -> string { 6 | string output; 7 | for(char c : input) { 8 | if(c == '&' ) { output.append("&" ); continue; } 9 | if(c == '<' ) { output.append("<" ); continue; } 10 | if(c == '>' ) { output.append(">" ); continue; } 11 | if(c == '"' ) { output.append("""); continue; } 12 | if(c == '\'') { output.append("'"); continue; } 13 | output.append(c); 14 | } 15 | return output; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /dsp/iir/dc-removal.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | //DC offset removal IIR filter 6 | 7 | namespace nall::DSP::IIR { 8 | 9 | struct DCRemoval { 10 | auto reset() -> void; 11 | auto process(double in) -> double; //normalized sample (-1.0 to +1.0) 12 | 13 | private: 14 | double x; 15 | double y; 16 | }; 17 | 18 | inline auto DCRemoval::reset() -> void { 19 | x = 0.0; 20 | y = 0.0; 21 | } 22 | 23 | inline auto DCRemoval::process(double in) -> double { 24 | x = 0.999 * x + in - y; 25 | y = in; 26 | return x; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /decode/mtf.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //move to front 4 | 5 | namespace nall::Decode { 6 | 7 | inline auto MTF(array_view input) -> vector { 8 | vector output; 9 | output.resize(input.size()); 10 | 11 | uint8_t order[256]; 12 | for(uint n : range(256)) order[n] = n; 13 | 14 | for(uint offset : range(input.size())) { 15 | uint data = input[offset]; 16 | uint value = order[data]; 17 | output[offset] = value; 18 | memory::move(&order[1], &order[0], data); 19 | order[0] = value; 20 | } 21 | 22 | return output; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /inline-if.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #warning "these defines break if statements with multiple parameters to templates" 3 | 4 | #define if1(statement) if(statement) 5 | #define if2(condition, false) ([&](auto&& value) -> decltype(condition) { \ 6 | return (bool)value ? value : (decltype(condition))false; \ 7 | })(condition) 8 | #define if3(condition, true, false) ((condition) ? (true) : (decltype(true))(false)) 9 | #define if4(type, condition, true, false) ((condition) ? (type)(true) : (type)(false)) 10 | #define if_(_1, _2, _3, _4, name, ...) name 11 | #define if(...) if_(__VA_ARGS__, if4, if3, if2, if1)(__VA_ARGS__) 12 | -------------------------------------------------------------------------------- /cd/sync.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::CD::Sync { 4 | 5 | inline auto create(array_span sector) -> bool { 6 | if(sector.size() != 12 && sector.size() != 2352) return false; 7 | 8 | for(uint n : range(12)) { 9 | sector[n] = ((n == 0 || n == 11) ? 0x00 : 0xff); 10 | } 11 | 12 | return true; 13 | } 14 | 15 | // 16 | 17 | inline auto verify(array_view sector) -> bool { 18 | if(sector.size() != 12 && sector.size() != 2352) return false; 19 | 20 | for(uint n : range(12)) { 21 | if(sector[n] != ((n == 0 || n == 11) ? 0x00 : 0xff)) return false; 22 | } 23 | 24 | return true; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /property.hpp: -------------------------------------------------------------------------------- 1 | #if !defined(property) 2 | #define property1(declaration) public: declaration 3 | #define property2(declaration, getter) public: __declspec(property(get=getter)) declaration; protected: declaration##_ 4 | #define property3(declaration, getter, setter) public: __declspec(property(get=getter, put=setter)) declaration; protected: declaration##_ 5 | #define property_(_1, _2, _3, name, ...) name 6 | #define property(...) property_(__VA_ARGS__, property3, property2, property1)(__VA_ARGS__) 7 | #else 8 | #undef property1 9 | #undef property2 10 | #undef property3 11 | #undef property_ 12 | #undef property 13 | #endif 14 | -------------------------------------------------------------------------------- /counting-sort.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall { 6 | 7 | //counting sort by powers of two: used to implement radix sort 8 | template 9 | auto counting_sort(T* output, const T* input, uint size) -> void { 10 | static_assert(Bits >= 1 && Bits <= 20, "must be between 1 and 20 bits"); 11 | enum : uint { Base = 1 << Bits, Mask = Base - 1 }; 12 | 13 | uint64_t count[Base] = {}, last = 0; 14 | for(uint n : range(size)) ++count[(input[n] >> Shift) & Mask]; 15 | for(uint n : range(Base)) last += count[n], count[n] = last - count[n]; 16 | for(uint n : range(size)) output[count[(input[n] >> Shift) & Mask]++] = input[n]; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /encode/mtf.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //move to front 4 | 5 | namespace nall::Encode { 6 | 7 | inline auto MTF(array_view input) -> vector { 8 | vector output; 9 | output.resize(input.size()); 10 | 11 | uint8_t order[256]; 12 | for(uint n : range(256)) order[n] = n; 13 | 14 | for(uint offset : range(input.size())) { 15 | uint data = input[offset]; 16 | for(uint index : range(256)) { 17 | uint value = order[index]; 18 | if(value == data) { 19 | output[offset] = index; 20 | memory::move(&order[1], &order[0], index); 21 | order[0] = value; 22 | break; 23 | } 24 | } 25 | } 26 | 27 | return output; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /windows/guard.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NALL_WINDOWS_GUARD_HPP 2 | #define NALL_WINDOWS_GUARD_HPP 3 | 4 | #define boolean WindowsBoolean 5 | #define interface WindowsInterface 6 | 7 | #undef UNICODE 8 | #undef WINVER 9 | #undef WIN32_LEAN_AND_LEAN 10 | #undef _WIN32_WINNT 11 | #undef _WIN32_IE 12 | #undef __MSVCRT_VERSION__ 13 | #undef NOMINMAX 14 | #undef PATH_MAX 15 | 16 | #define UNICODE 17 | #define WINVER 0x0601 18 | #define WIN32_LEAN_AND_MEAN 19 | #define _WIN32_WINNT WINVER 20 | #define _WIN32_IE WINVER 21 | #define __MSVCRT_VERSION__ WINVER 22 | #define NOMINMAX 23 | #define PATH_MAX 260 24 | 25 | #else 26 | #undef NALL_WINDOWS_GUARD_HPP 27 | 28 | #undef boolean 29 | #undef interface 30 | 31 | #undef far 32 | #undef near 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /instance.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template 6 | struct Instance { 7 | ~Instance() { 8 | destruct(); 9 | } 10 | 11 | auto operator()() -> T& { 12 | return instance.object; 13 | } 14 | 15 | template 16 | auto construct(P&&... p) { 17 | if(constructed) return; 18 | constructed = true; 19 | new((void*)(&instance.object)) T(forward

(p)...); 20 | } 21 | 22 | auto destruct() -> void { 23 | if(!constructed) return; 24 | constructed = false; 25 | instance.object.~T(); 26 | } 27 | 28 | private: 29 | bool constructed = false; 30 | union Union { 31 | Union() {} 32 | ~Union() {} 33 | 34 | T object; 35 | char storage[sizeof(T)]; 36 | } instance; 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /algorithm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #undef min 6 | #undef max 7 | 8 | namespace nall { 9 | 10 | template constexpr auto min(const T& t, const U& u) -> T { 11 | return t < u ? t : (T)u; 12 | } 13 | 14 | template constexpr auto min(const T& t, const U& u, P&&... p) -> T { 15 | return t < u ? min(t, forward

(p)...) : min(u, forward

(p)...); 16 | } 17 | 18 | template constexpr auto max(const T& t, const U& u) -> T { 19 | return t > u ? t : (T)u; 20 | } 21 | 22 | template constexpr auto max(const T& t, const U& u, P&&... p) -> T { 23 | return t > u ? max(t, forward

(p)...) : max(u, forward

(p)...); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /vector/assign.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template auto vector::operator=(const vector& source) -> vector& { 6 | if(this == &source) return *this; 7 | _pool = memory::allocate(source._size); 8 | _size = source._size; 9 | _left = 0; 10 | _right = 0; 11 | for(uint64_t n : range(_size)) new(_pool + n) T(source._pool[n]); 12 | return *this; 13 | } 14 | 15 | template auto vector::operator=(vector&& source) -> vector& { 16 | if(this == &source) return *this; 17 | _pool = source._pool; 18 | _size = source._size; 19 | _left = source._left; 20 | _right = source._right; 21 | source._pool = nullptr; 22 | source._size = 0; 23 | source._left = 0; 24 | source._right = 0; 25 | return *this; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /utility.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall { 6 | 7 | using std::tuple; 8 | 9 | template struct base_from_member { 10 | base_from_member(T value) : value(value) {} 11 | T value; 12 | }; 13 | 14 | template struct castable { 15 | operator To&() { return (To&)value; } 16 | operator const To&() const { return (const To&)value; } 17 | operator With&() { return value; } 18 | operator const With&() const { return value; } 19 | auto& operator=(const With& value) { return this->value = value; } 20 | With value; 21 | }; 22 | 23 | template inline auto allocate(uint size, const T& value) -> T* { 24 | T* array = new T[size]; 25 | for(uint i = 0; i < size; i++) array[i] = value; 26 | return array; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /arithmetic/barrett.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template struct BarrettReduction { 6 | using type = typename ArithmeticNatural<1 * Bits>::type; 7 | using pair = typename ArithmeticNatural<2 * Bits>::type; 8 | 9 | explicit BarrettReduction(type modulo) : modulo(modulo), factor(pair(1) + -pair(modulo) / modulo) {} 10 | 11 | //return => value % modulo 12 | auto operator()(pair value) const -> type { 13 | pair hi, lo; 14 | mul(value, factor, hi, lo); 15 | pair remainder = value - hi * modulo; 16 | return remainder < modulo ? remainder : remainder - modulo; 17 | } 18 | 19 | private: 20 | const pair modulo; 21 | const pair factor; 22 | }; 23 | 24 | template auto operator%(T value, const BarrettReduction& modulo) { 25 | return modulo(value); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /beat/archive/extract.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace nall::Beat::Archive { 7 | 8 | auto extract(Container& container) -> bool { 9 | function extract = [&](auto metadata) { 10 | if(metadata.name() != "path" && metadata.name() != "file") return; 11 | shared_pointer node = new Node; 12 | if(node->unserialize(container.memory, metadata)) { 13 | container.nodes.append(node); 14 | } 15 | if(metadata.name() != "path") return; 16 | for(auto node : metadata) extract(node); 17 | }; 18 | 19 | container.nodes.reset(); 20 | auto document = BML::unserialize(container.metadata); 21 | for(auto node : document["archive"]) extract(node); 22 | container.sort(); 23 | 24 | return true; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /image/static.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline auto image::bitDepth(uint64_t color) -> uint { 6 | uint depth = 0; 7 | if(color) while((color & 1) == 0) color >>= 1; 8 | while((color & 1) == 1) { color >>= 1; depth++; } 9 | return depth; 10 | } 11 | 12 | inline auto image::bitShift(uint64_t color) -> uint { 13 | uint shift = 0; 14 | if(color) while((color & 1) == 0) { color >>= 1; shift++; } 15 | return shift; 16 | } 17 | 18 | inline auto image::normalize(uint64_t color, uint sourceDepth, uint targetDepth) -> uint64_t { 19 | if(sourceDepth == 0 || targetDepth == 0) return 0; 20 | while(sourceDepth < targetDepth) { 21 | color = (color << sourceDepth) | color; 22 | sourceDepth += sourceDepth; 23 | } 24 | if(targetDepth < sourceDepth) color >>= (sourceDepth - targetDepth); 25 | return color; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /windows/shared-memory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | struct shared_memory { 6 | shared_memory() = default; 7 | shared_memory(const shared_memory&) = delete; 8 | auto operator=(const shared_memory&) -> shared_memory& = delete; 9 | 10 | ~shared_memory() { 11 | reset(); 12 | } 13 | 14 | explicit operator bool() const { return false; } 15 | auto empty() const -> bool { return true; } 16 | auto size() const -> uint { return 0; } 17 | auto acquired() const -> bool { return false; } 18 | auto acquire() -> uint8_t* { return nullptr; } 19 | auto release() -> void {} 20 | auto reset() -> void {} 21 | auto create(const string& name, uint size) -> bool { return false; } 22 | auto remove() -> void {} 23 | auto open(const string& name, uint size) -> bool { return false; } 24 | auto close() -> void {} 25 | }; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /encode/url.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Encode { 4 | 5 | inline auto URL(string_view input) -> string { 6 | string output; 7 | for(auto c : input) { 8 | //unreserved characters 9 | if(c >= 'A' && c <= 'Z') { output.append(c); continue; } 10 | if(c >= 'a' && c <= 'z') { output.append(c); continue; } 11 | if(c >= '0' && c <= '9') { output.append(c); continue; } 12 | if(c == '-' || c == '_' || c == '.' || c == '~') { output.append(c); continue; } 13 | 14 | //special characters 15 | if(c == ' ') { output.append('+'); continue; } 16 | 17 | //reserved characters 18 | uint hi = (c >> 4) & 15; 19 | uint lo = (c >> 0) & 15; 20 | output.append('%'); 21 | output.append((char)(hi < 10 ? ('0' + hi) : ('a' + hi - 10))); 22 | output.append((char)(lo < 10 ? ('0' + lo) : ('a' + lo - 10))); 23 | } 24 | return output; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /cd/scrambler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::CD::Scrambler { 4 | 5 | //polynomial(x) = x^15 + x + 1 6 | inline auto polynomial(uint x) -> uint8_t { 7 | static uint8_t lookup[2340]{}; 8 | static bool once = false; 9 | if(!once) { once = true; 10 | uint16_t shift = 0x0001; 11 | for(uint n : range(2340)) { 12 | lookup[n] = shift; 13 | for(uint b : range(8)) { 14 | bool carry = shift & 1 ^ shift >> 1 & 1; 15 | shift = (carry << 15 | shift) >> 1; 16 | } 17 | } 18 | } 19 | return lookup[x]; 20 | } 21 | 22 | // 23 | 24 | inline auto transform(array_span sector) -> bool { 25 | if(sector.size() == 2352) sector += 12; //header is not scrambled 26 | if(sector.size() != 2340) return false; //F1 frames only 27 | 28 | for(uint index : range(2340)) { 29 | sector[index] ^= polynomial(index); 30 | } 31 | 32 | return true; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /primitives.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace nall { 8 | struct Boolean; 9 | template struct Natural; 10 | template struct Integer; 11 | template struct Real; 12 | } 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace nall { 24 | template auto Natural::integer() const -> Integer { return Integer(*this); } 25 | template auto Integer::natural() const -> Natural { return Natural(*this); } 26 | } 27 | -------------------------------------------------------------------------------- /decode/huffman.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Decode { 4 | 5 | inline auto Huffman(array_view input) -> vector { 6 | vector output; 7 | 8 | uint size = 0; 9 | for(uint byte : range(8)) size |= *input++ << byte * 8; 10 | output.reserve(size); 11 | 12 | uint byte = 0, bits = 0; 13 | auto read = [&]() -> bool { 14 | if(bits == 0) bits = 8, byte = *input++; 15 | return byte >> --bits & 1; 16 | }; 17 | 18 | uint nodes[256][2] = {}; 19 | for(uint offset : range(256)) { 20 | for(uint index : range(9)) nodes[offset][0] = nodes[offset][0] << 1 | read(); 21 | for(uint index : range(9)) nodes[offset][1] = nodes[offset][1] << 1 | read(); 22 | } 23 | 24 | uint node = 511; 25 | while(output.size() < size) { 26 | node = nodes[node - 256][read()]; 27 | if(node < 256) { 28 | output.append(node); 29 | node = 511; 30 | } 31 | } 32 | 33 | return output; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /matrix-multiply.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //matrix multiplication primitives 4 | //used in: ruby/opengl/quark 5 | 6 | namespace nall { 7 | 8 | template inline auto MatrixMultiply( 9 | T* output, 10 | const T* xdata, uint xrows, uint xcols, 11 | const T* ydata, uint yrows, uint ycols 12 | ) -> void { 13 | if(xcols != yrows) return; 14 | 15 | for(uint y : range(xrows)) { 16 | for(uint x : range(ycols)) { 17 | T sum = 0; 18 | for(uint z : range(xcols)) { 19 | sum += xdata[y * xcols + z] * ydata[z * ycols + x]; 20 | } 21 | *output++ = sum; 22 | } 23 | } 24 | } 25 | 26 | template inline auto MatrixMultiply( 27 | const T* xdata, uint xrows, uint xcols, 28 | const T* ydata, uint yrows, uint ycols 29 | ) -> vector { 30 | vector output; 31 | output.resize(xrows * ycols); 32 | MatrixMultiply(output.data(), xdata, xrows, xcols, ydata, yrows, ycols); 33 | return output; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /pointer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template 6 | struct pointer { 7 | explicit operator bool() const { return value; } 8 | 9 | pointer() = default; 10 | pointer(T* source) { value = source; } 11 | pointer(const pointer& source) { value = source.value; } 12 | 13 | auto& operator=(T* source) { value = source; return *this; } 14 | auto& operator=(const pointer& source) { value = source.value; return *this; } 15 | 16 | auto operator()() -> T* { return value; } 17 | auto operator()() const -> const T* { return value; } 18 | 19 | auto operator->() -> T* { return value; } 20 | auto operator->() const -> const T* { return value; } 21 | 22 | auto operator*() -> T& { return *value; } 23 | auto operator*() const -> const T& { return *value; } 24 | 25 | auto reset() -> void { value = nullptr; } 26 | 27 | auto data() -> T* { return value; } 28 | auto data() const -> const T* { return value; } 29 | 30 | private: 31 | T* value = nullptr; 32 | }; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /xorg/guard.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NALL_XORG_GUARD_HPP 2 | #define NALL_XORG_GUARD_HPP 3 | 4 | #define Atom XlibAtom 5 | #define Display XlibDisplay 6 | #define Font XlibFont 7 | #define Screen XlibScreen 8 | #define Window XlibWindow 9 | 10 | #else 11 | #undef NALL_XORG_GUARD_HPP 12 | 13 | #undef Atom 14 | #undef Display 15 | #undef Font 16 | #undef Screen 17 | #undef Window 18 | 19 | #undef Above 20 | #undef Below 21 | #undef Bool 22 | 23 | #ifndef NALL_XORG_GUARD_CONSTANTS 24 | #define NALL_XORG_GUARD_CONSTANTS 25 | enum XlibConstants : int { 26 | XlibButton1 = Button1, 27 | XlibButton2 = Button2, 28 | XlibButton3 = Button3, 29 | XlibButton4 = Button4, 30 | XlibButton5 = Button5, 31 | XlibCurrentTime = CurrentTime, 32 | XlibFalse = False, 33 | XlibNone = None, 34 | XlibTrue = True, 35 | }; 36 | #endif 37 | 38 | #undef Button1 39 | #undef Button2 40 | #undef Button3 41 | #undef Button4 42 | #undef Button5 43 | #undef CurrentTime 44 | #undef False 45 | #undef None 46 | #undef True 47 | 48 | #undef MAX 49 | #undef MIN 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /cd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* CD-ROM sector functions. 4 | * 5 | * Implemented: 6 | * eight-to-fourteen modulation (encoding and decoding) 7 | * sync header creation and verification 8 | * error detection code creation and verification 9 | * reed-solomon product-code creation and verification 10 | * sector scrambling and descrambling (currently unverified) 11 | * 12 | * Unimplemented: 13 | * reed-solomon product-code correction 14 | * cross-interleave reed-solomon creation, verification, and correction 15 | * CD-ROM XA mode 2 forms 1 & 2 support 16 | * subcode insertion and removal 17 | * subcode decoding from CUE files 18 | * channel frame expansion and reduction 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | -------------------------------------------------------------------------------- /primitives/boolean.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | struct Boolean { 6 | static constexpr auto bits() -> uint { return 1; } 7 | using btype = bool; 8 | 9 | Boolean() : data(false) {} 10 | template Boolean(const T& value) : data(value) {} 11 | explicit Boolean(const char* value) { data = !strcmp(value, "true"); } 12 | 13 | operator bool() const { return data; } 14 | template auto& operator=(const T& value) { data = value; return *this; } 15 | 16 | auto flip() { return data ^= 1; } 17 | auto raise() { return data == 0 ? data = 1, true : false; } 18 | auto lower() { return data == 1 ? data = 0, true : false; } 19 | 20 | auto flip(bool value) { return data != value ? (data = value, true) : false; } 21 | auto raise(bool value) { return !data && value ? (data = value, true) : (data = value, false); } 22 | auto lower(bool value) { return data && !value ? (data = value, true) : (data = value, false); } 23 | 24 | auto serialize(serializer& s) { s(data); } 25 | 26 | private: 27 | btype data; 28 | }; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /decode/bwt.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //burrows-wheeler transform 4 | 5 | #include 6 | 7 | namespace nall::Decode { 8 | 9 | inline auto BWT(array_view input) -> vector { 10 | vector output; 11 | 12 | uint size = 0; 13 | for(uint byte : range(8)) size |= *input++ << byte * 8; 14 | output.resize(size); 15 | 16 | uint I = 0; 17 | for(uint byte : range(8)) I |= *input++ << byte * 8; 18 | 19 | auto suffixes = SuffixArray(input); 20 | 21 | auto L = input; 22 | auto F = new uint8_t[size]; 23 | for(uint offset : range(size)) F[offset] = L[suffixes[offset + 1]]; 24 | 25 | uint64_t K[256] = {}; 26 | auto C = new int[size]; 27 | for(uint i : range(size)) { 28 | C[i] = K[L[i]]; 29 | K[L[i]]++; 30 | } 31 | 32 | int M[256]; 33 | memory::fill(M, 256, -1); 34 | for(uint i : range(size)) { 35 | if(M[F[i]] == -1) M[F[i]] = i; 36 | } 37 | 38 | uint i = I; 39 | for(uint j : reverse(range(size))) { 40 | output[j] = L[i]; 41 | i = C[i] + M[L[i]]; 42 | } 43 | 44 | return output; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /decode/rle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Decode { 4 | 5 | template //S = word size; M = match length 6 | inline auto RLE(array_view input) -> vector { 7 | vector output; 8 | 9 | auto load = [&]() -> uint8_t { 10 | return input ? *input++ : 0; 11 | }; 12 | 13 | uint base = 0; 14 | uint64_t size = 0; 15 | for(uint byte : range(8)) size |= load() << byte * 8; 16 | output.resize(size); 17 | 18 | auto read = [&]() -> uint64_t { 19 | uint64_t value = 0; 20 | for(uint byte : range(S)) value |= load() << byte * 8; 21 | return value; 22 | }; 23 | 24 | auto write = [&](uint64_t value) -> void { 25 | if(base >= size) return; 26 | for(uint byte : range(S)) output[base++] = value >> byte * 8; 27 | }; 28 | 29 | while(base < size) { 30 | auto byte = load(); 31 | if(byte < 128) { 32 | byte++; 33 | while(byte--) write(read()); 34 | } else { 35 | auto value = read(); 36 | byte = (byte & 127) + M; 37 | while(byte--) write(value); 38 | } 39 | } 40 | 41 | return output; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /string/utf8.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | //note: this function assumes the string contains valid UTF-8 characters 6 | //invalid characters will result in an incorrect result from this function 7 | //invalid case 1: byte 1 == 0b'01xxxxxx 8 | //invalid case 2: bytes 2-4 != 0b'10xxxxxx 9 | //invalid case 3: end of string without bytes 2-4 present 10 | inline auto characters(string_view self, int offset, int length) -> uint { 11 | uint characters = 0; 12 | if(offset < 0) offset = self.size() - abs(offset); 13 | if(offset >= 0 && offset < self.size()) { 14 | if(length < 0) length = self.size() - offset; 15 | if(length >= 0) { 16 | for(int index = offset; index < offset + length;) { 17 | auto byte = self.data()[index++]; 18 | if((byte & 0b111'00000) == 0b110'00000) index += 1; 19 | if((byte & 0b1111'0000) == 0b1110'0000) index += 2; 20 | if((byte & 0b11111'000) == 0b11110'000) index += 3; 21 | characters++; 22 | } 23 | } 24 | } 25 | return characters; 26 | } 27 | 28 | inline auto string::characters(int offset, int length) const -> uint { 29 | return nall::characters(*this, offset, length); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /decode/base64.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Decode { 4 | 5 | inline auto Base64(const string& text) -> vector { 6 | static bool initialized = false; 7 | static uint8_t lookup[256] = {0}; 8 | if(!initialized) { 9 | initialized = true; 10 | for(uint n : range(26)) lookup['A' + n] = n; 11 | for(uint n : range(26)) lookup['a' + n] = n + 26; 12 | for(uint n : range(10)) lookup['0' + n] = n + 52; 13 | lookup['+'] = lookup['-'] = 62; 14 | lookup['/'] = lookup['_'] = 63; 15 | } 16 | 17 | vector result; 18 | uint8_t buffer, output; 19 | for(uint n : range(text.size())) { 20 | uint8_t buffer = lookup[text[n]]; 21 | 22 | switch(n & 3) { 23 | case 0: 24 | output = buffer << 2; 25 | break; 26 | 27 | case 1: 28 | result.append(output | buffer >> 4); 29 | output = (buffer & 15) << 4; 30 | break; 31 | 32 | case 2: 33 | result.append(output | buffer >> 2); 34 | output = (buffer & 3) << 6; 35 | break; 36 | 37 | case 3: 38 | result.append(output | buffer); 39 | break; 40 | } 41 | } 42 | 43 | if(text.size() & 3) result.append(output | buffer); 44 | return result; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /vfs/disk.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall::vfs { 6 | 7 | struct disk : file { 8 | static auto open(string location_, mode mode_) -> shared_pointer { 9 | auto instance = shared_pointer{new disk}; 10 | if(!instance->_open(location_, mode_)) return {}; 11 | return instance; 12 | } 13 | 14 | auto size() const -> uintmax override { 15 | return _fp.size(); 16 | } 17 | 18 | auto offset() const -> uintmax override { 19 | return _fp.offset(); 20 | } 21 | 22 | auto seek(intmax offset_, index index_) -> void override { 23 | _fp.seek(offset_, (uint)index_); 24 | } 25 | 26 | auto read() -> uint8_t override { 27 | return _fp.read(); 28 | } 29 | 30 | auto write(uint8_t data_) -> void override { 31 | _fp.write(data_); 32 | } 33 | 34 | auto flush() -> void override { 35 | _fp.flush(); 36 | } 37 | 38 | private: 39 | disk() = default; 40 | disk(const disk&) = delete; 41 | auto operator=(const disk&) -> disk& = delete; 42 | 43 | auto _open(string location_, mode mode_) -> bool { 44 | if(!_fp.open(location_, (uint)mode_)) return false; 45 | return true; 46 | } 47 | 48 | file_buffer _fp; 49 | }; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /string/eval/node.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Eval { 4 | 5 | struct Node { 6 | enum class Type : uint { 7 | Null, 8 | Literal, 9 | Function, Subscript, Member, SuffixIncrement, SuffixDecrement, 10 | Reference, Dereference, LogicalNot, BitwiseNot, Positive, Negative, PrefixIncrement, PrefixDecrement, 11 | Multiply, Divide, Modulo, 12 | Add, Subtract, 13 | RotateLeft, RotateRight, ShiftLeft, ShiftRight, 14 | BitwiseAnd, BitwiseOr, BitwiseXor, 15 | Concatenate, 16 | Equal, NotEqual, LessThanEqual, GreaterThanEqual, LessThan, GreaterThan, 17 | LogicalAnd, LogicalOr, 18 | Coalesce, Condition, 19 | Assign, Create, //all assignment operators have the same precedence 20 | AssignMultiply, AssignDivide, AssignModulo, 21 | AssignAdd, AssignSubtract, 22 | AssignRotateLeft, AssignRotateRight, AssignShiftLeft, AssignShiftRight, 23 | AssignBitwiseAnd, AssignBitwiseOr, AssignBitwiseXor, 24 | AssignConcatenate, 25 | Separator, 26 | }; 27 | 28 | Type type; 29 | string literal; 30 | vector link; 31 | 32 | Node() : type(Type::Null) {} 33 | Node(Type type) : type(type) {} 34 | ~Node() { for(auto& node : link) delete node; } 35 | }; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /decode/html.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Decode { 4 | 5 | inline auto HTML(const string& input) -> string { 6 | string output; 7 | for(uint n = 0; n < input.size();) { 8 | if(input[n] == '&') { 9 | if(input(n + 1) == 'a' && input(n + 2) == 'm' && input(n + 3) == 'p' && input(n + 4) == ';') { 10 | output.append('&'); 11 | n += 5; 12 | continue; 13 | } 14 | if(input(n + 1) == 'l' && input(n + 2) == 't' && input(n + 3) == ';') { 15 | output.append('<'); 16 | n += 4; 17 | continue; 18 | } 19 | if(input(n + 1) == 'g' && input(n + 2) == 't' && input(n + 3) == ';') { 20 | output.append('>'); 21 | n += 4; 22 | continue; 23 | } 24 | if(input(n + 1) == 'q' && input(n + 2) == 'u' && input(n + 3) == 'o' && input(n + 4) == 't' && input(n + 5) == ';') { 25 | output.append('"'); 26 | n += 6; 27 | continue; 28 | } 29 | if(input(n + 1) == 'a' && input(n + 2) == 'p' && input(n + 3) == 'o' && input(n + 4) == 's' && input(n + 5) == ';') { 30 | output.append('\''); 31 | n += 6; 32 | continue; 33 | } 34 | } 35 | output.append(input[n++]); 36 | } 37 | return output; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /vector/specialization/uint8_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template<> struct vector : vector_base { 6 | using type = vector; 7 | using vector_base::vector_base; 8 | 9 | template auto appendl(U value, uint size) -> void { 10 | for(uint byte : range(size)) append(uint8_t(value >> byte * 8)); 11 | } 12 | 13 | template auto appendm(U value, uint size) -> void { 14 | for(uint byte : nall::reverse(range(size))) append(uint8_t(value >> byte * 8)); 15 | } 16 | 17 | //note: string_view is not declared here yet ... 18 | auto appends(array_view memory) -> void { 19 | for(uint8_t byte : memory) append(byte); 20 | } 21 | 22 | template auto readl(int offset, uint size) -> U { 23 | if(offset < 0) offset = this->size() - abs(offset); 24 | U value = 0; 25 | for(uint byte : range(size)) value |= (U)operator[](offset + byte) << byte * 8; 26 | return value; 27 | } 28 | 29 | auto view(uint offset, uint length) -> array_view { 30 | #ifdef DEBUG 31 | struct out_of_bounds {}; 32 | if(offset + length >= size()) throw out_of_bounds{}; 33 | #endif 34 | return {data() + offset, length}; 35 | } 36 | }; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /dsp/iir/one-pole.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | //one-pole first-order IIR filter 6 | 7 | namespace nall::DSP::IIR { 8 | 9 | struct OnePole { 10 | enum class Type : uint { 11 | LowPass, 12 | HighPass, 13 | }; 14 | 15 | auto reset(Type type, double cutoffFrequency, double samplingFrequency) -> void; 16 | auto process(double in) -> double; //normalized sample (-1.0 to +1.0) 17 | 18 | private: 19 | Type type; 20 | double cutoffFrequency; 21 | double samplingFrequency; 22 | double a0, b1; //coefficients 23 | double z1; //first-order IIR 24 | }; 25 | 26 | inline auto OnePole::reset(Type type, double cutoffFrequency, double samplingFrequency) -> void { 27 | this->type = type; 28 | this->cutoffFrequency = cutoffFrequency; 29 | this->samplingFrequency = samplingFrequency; 30 | 31 | z1 = 0.0; 32 | double x = cos(2.0 * Math::Pi * cutoffFrequency / samplingFrequency); 33 | if(type == Type::LowPass) { 34 | b1 = +2.0 - x - sqrt((+2.0 - x) * (+2.0 - x) - 1); 35 | a0 = 1.0 - b1; 36 | } else { 37 | b1 = -2.0 - x + sqrt((-2.0 - x) * (-2.0 - x) - 1); 38 | a0 = 1.0 + b1; 39 | } 40 | } 41 | 42 | inline auto OnePole::process(double in) -> double { 43 | return z1 = in * a0 + z1 * b1; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /hash/crc32.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall::Hash { 6 | 7 | struct CRC32 : Hash { 8 | using Hash::input; 9 | 10 | CRC32(array_view buffer = {}) { 11 | reset(); 12 | input(buffer); 13 | } 14 | 15 | auto reset() -> void override { 16 | checksum = ~0; 17 | } 18 | 19 | auto input(uint8_t value) -> void override { 20 | checksum = (checksum >> 8) ^ table(checksum ^ value); 21 | } 22 | 23 | auto output() const -> vector { 24 | vector result; 25 | for(auto n : reverse(range(4))) result.append(~checksum >> n * 8); 26 | return result; 27 | } 28 | 29 | auto value() const -> uint32_t { 30 | return ~checksum; 31 | } 32 | 33 | private: 34 | static auto table(uint8_t index) -> uint32_t { 35 | static uint32_t table[256] = {0}; 36 | static bool initialized = false; 37 | 38 | if(!initialized) { 39 | initialized = true; 40 | for(auto index : range(256)) { 41 | uint32_t crc = index; 42 | for(auto bit : range(8)) { 43 | crc = (crc >> 1) ^ (crc & 1 ? 0xedb8'8320 : 0); 44 | } 45 | table[index] = crc; 46 | } 47 | } 48 | 49 | return table[index]; 50 | } 51 | 52 | uint32_t checksum = 0; 53 | }; 54 | 55 | } 56 | -------------------------------------------------------------------------------- /vector/access.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template auto vector::operator[](uint64_t offset) -> T& { 6 | #ifdef DEBUG 7 | struct out_of_bounds {}; 8 | if(offset >= size()) throw out_of_bounds{}; 9 | #endif 10 | return _pool[offset]; 11 | } 12 | 13 | template auto vector::operator[](uint64_t offset) const -> const T& { 14 | #ifdef DEBUG 15 | struct out_of_bounds {}; 16 | if(offset >= size()) throw out_of_bounds{}; 17 | #endif 18 | return _pool[offset]; 19 | } 20 | 21 | template auto vector::operator()(uint64_t offset) -> T& { 22 | while(offset >= size()) append(T()); 23 | return _pool[offset]; 24 | } 25 | 26 | template auto vector::operator()(uint64_t offset, const T& value) const -> const T& { 27 | if(offset >= size()) return value; 28 | return _pool[offset]; 29 | } 30 | 31 | template auto vector::left() -> T& { 32 | return _pool[0]; 33 | } 34 | 35 | template auto vector::left() const -> const T& { 36 | return _pool[0]; 37 | } 38 | 39 | template auto vector::right() -> T& { 40 | return _pool[_size - 1]; 41 | } 42 | 43 | template auto vector::right() const -> const T& { 44 | return _pool[_size - 1]; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /hash/crc16.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall::Hash { 6 | 7 | struct CRC16 : Hash { 8 | using Hash::input; 9 | 10 | CRC16(array_view buffer = {}) { 11 | reset(); 12 | input(buffer); 13 | } 14 | 15 | auto reset() -> void override { 16 | checksum = ~0; 17 | } 18 | 19 | auto input(uint8_t value) -> void override { 20 | checksum = (checksum >> 8) ^ table(checksum ^ value); 21 | } 22 | 23 | auto output() const -> vector override { 24 | vector result; 25 | for(auto n : reverse(range(2))) result.append(~checksum >> n * 8); 26 | return result; 27 | } 28 | 29 | auto value() const -> uint16_t { 30 | return ~checksum; 31 | } 32 | 33 | private: 34 | static auto table(uint8_t index) -> uint16_t { 35 | static uint16_t table[256] = {0}; 36 | static bool initialized = false; 37 | 38 | if(!initialized) { 39 | initialized = true; 40 | for(auto index : range(256)) { 41 | uint16_t crc = index; 42 | for(auto bit : range(8)) { 43 | crc = (crc >> 1) ^ (crc & 1 ? 0x8408 : 0); 44 | } 45 | table[index] = crc; 46 | } 47 | } 48 | 49 | return table[index]; 50 | } 51 | 52 | uint16_t checksum = 0; 53 | }; 54 | 55 | } 56 | -------------------------------------------------------------------------------- /hash/crc64.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall::Hash { 6 | 7 | struct CRC64 : Hash { 8 | using Hash::input; 9 | 10 | CRC64(array_view buffer = {}) { 11 | reset(); 12 | input(buffer); 13 | } 14 | 15 | auto reset() -> void override { 16 | checksum = ~0; 17 | } 18 | 19 | auto input(uint8_t value) -> void override { 20 | checksum = (checksum >> 8) ^ table(checksum ^ value); 21 | } 22 | 23 | auto output() const -> vector { 24 | vector result; 25 | for(auto n : reverse(range(8))) result.append(~checksum >> n * 8); 26 | return result; 27 | } 28 | 29 | auto value() const -> uint64_t { 30 | return ~checksum; 31 | } 32 | 33 | private: 34 | static auto table(uint8_t index) -> uint64_t { 35 | static uint64_t table[256] = {0}; 36 | static bool initialized = false; 37 | 38 | if(!initialized) { 39 | initialized = true; 40 | for(auto index : range(256)) { 41 | uint64_t crc = index; 42 | for(auto bit : range(8)) { 43 | crc = (crc >> 1) ^ (crc & 1 ? 0xc96c'5795'd787'0f42 : 0); 44 | } 45 | table[index] = crc; 46 | } 47 | } 48 | 49 | return table[index]; 50 | } 51 | 52 | uint64_t checksum = 0; 53 | }; 54 | 55 | } 56 | -------------------------------------------------------------------------------- /decode/base.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall::Decode { 6 | 7 | template inline auto Base(const string& value) -> T { 8 | static const string format = 9 | Bits == 2 ? "01" 10 | : Bits == 8 ? "01234567" 11 | : Bits == 10 ? "0123456789" 12 | : Bits == 16 ? "0123456789abcdef" 13 | : Bits == 32 ? "0123456789abcdefghijklmnopqrstuv" 14 | : Bits == 34 ? "023456789abcdefghijkmnopqrstuvwxyz" //1l 15 | : Bits == 36 ? "0123456789abcdefghijklmnopqrstuvwxyz" 16 | : Bits == 57 ? "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" //01IOl 17 | : Bits == 62 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 18 | : Bits == 64 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{}" 19 | : Bits == 85 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%()+,-.:;=@[]^_`{|}~" //\ "&'*/<>? 20 | : ""; 21 | static bool initialized = false; 22 | static uint8_t lookup[256] = {0}; 23 | if(!initialized) { 24 | initialized = true; 25 | for(uint n : range(format.size())) { 26 | lookup[format[n]] = n; 27 | } 28 | } 29 | 30 | T result = 0; 31 | for(auto byte : value) { 32 | result = result * Bits + lookup[byte]; 33 | } 34 | return result; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /literals.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline constexpr auto operator"" _Kibit(unsigned long long value) { return value * 1024 / 8; } 6 | inline constexpr auto operator"" _Mibit(unsigned long long value) { return value * 1024 * 1024 / 8; } 7 | inline constexpr auto operator"" _Gibit(unsigned long long value) { return value * 1024 * 1024 * 1024 / 8; } 8 | inline constexpr auto operator"" _Tibit(unsigned long long value) { return value * 1024 * 1024 * 1024 * 1024 / 8; } 9 | 10 | inline constexpr auto operator"" _KiB(unsigned long long value) { return value * 1024; } 11 | inline constexpr auto operator"" _MiB(unsigned long long value) { return value * 1024 * 1024; } 12 | inline constexpr auto operator"" _GiB(unsigned long long value) { return value * 1024 * 1024 * 1024; } 13 | inline constexpr auto operator"" _TiB(unsigned long long value) { return value * 1024 * 1024 * 1024 * 1024; } 14 | 15 | inline constexpr auto operator"" _KHz(unsigned long long value) { return value * 1000; } 16 | inline constexpr auto operator"" _MHz(unsigned long long value) { return value * 1000 * 1000; } 17 | inline constexpr auto operator"" _GHz(unsigned long long value) { return value * 1000 * 1000 * 1000; } 18 | inline constexpr auto operator"" _THz(unsigned long long value) { return value * 1000 * 1000 * 1000 * 1000; } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /decode/url.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Decode { 4 | 5 | //returns empty string on malformed content 6 | inline auto URL(string_view input) -> string { 7 | string output; 8 | for(uint n = 0; n < input.size();) { 9 | char c = input[n]; 10 | 11 | //unreserved characters 12 | if(c >= 'A' && c <= 'Z') { output.append(c); n++; continue; } 13 | if(c >= 'a' && c <= 'z') { output.append(c); n++; continue; } 14 | if(c >= '0' && c <= '9') { output.append(c); n++; continue; } 15 | if(c == '-' || c == '_' || c == '.' || c == '~') { output.append(c); n++; continue; } 16 | 17 | //special characters 18 | if(c == '+') { output.append(' '); n++; continue; } 19 | 20 | //reserved characters 21 | if(c != '%' || n + 2 >= input.size()) return ""; 22 | char hi = input[n + 1]; 23 | char lo = input[n + 2]; 24 | if(hi >= '0' && hi <= '9') hi -= '0'; 25 | else if(hi >= 'A' && hi <= 'F') hi -= 'A' - 10; 26 | else if(hi >= 'a' && hi <= 'f') hi -= 'a' - 10; 27 | else return ""; 28 | if(lo >= '0' && lo <= '9') lo -= '0'; 29 | else if(lo >= 'A' && lo <= 'F') lo -= 'A' - 10; 30 | else if(lo >= 'a' && lo <= 'f') lo -= 'a' - 10; 31 | else return ""; 32 | char byte = hi * 16 + lo; 33 | output.append(byte); 34 | n += 3; 35 | } 36 | return output; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /recompiler/amd64/emitter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct emitter { 4 | auto byte(u8 data) { 5 | span.write(data); 6 | } 7 | 8 | auto word(u16 data) { 9 | span.write(data >> 0); 10 | span.write(data >> 8); 11 | } 12 | 13 | auto dword(u32 data) { 14 | span.write(data >> 0); 15 | span.write(data >> 8); 16 | span.write(data >> 16); 17 | span.write(data >> 24); 18 | } 19 | 20 | auto qword(u64 data) { 21 | span.write(data >> 0); 22 | span.write(data >> 8); 23 | span.write(data >> 16); 24 | span.write(data >> 24); 25 | span.write(data >> 32); 26 | span.write(data >> 40); 27 | span.write(data >> 48); 28 | span.write(data >> 56); 29 | } 30 | 31 | auto rex(bool w, bool r, bool x, bool b) { 32 | u8 data = 0x40 | w << 3 | r << 2 | x << 1 | b << 0; 33 | if(data == 0x40) return; //rex prefix not needed 34 | byte(data); 35 | } 36 | 37 | auto modrm(u8 mod, u8 reg, u8 rm) { 38 | byte(mod << 6 | reg << 3 | rm << 0); 39 | } 40 | 41 | auto sib(u8 scale, u8 index, u8 base) { 42 | byte(scale << 6 | index << 3 | base << 0); 43 | } 44 | 45 | array_span span, origin; 46 | } emit; 47 | 48 | auto bind(array_span span) { 49 | emit.span = span; 50 | emit.origin = span; 51 | } 52 | 53 | auto size() const -> u32 { 54 | return emit.span.data() - emit.origin.data(); 55 | } 56 | -------------------------------------------------------------------------------- /traits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | //pull all type traits used by nall from std namespace into nall namespace 7 | //this removes the requirement to prefix type traits with std:: within nall 8 | 9 | namespace nall { 10 | using std::add_const; 11 | using std::conditional; 12 | using std::conditional_t; 13 | using std::decay; 14 | using std::declval; 15 | using std::enable_if; 16 | using std::enable_if_t; 17 | using std::false_type; 18 | using std::is_floating_point; 19 | using std::is_floating_point_v; 20 | using std::forward; 21 | using std::initializer_list; 22 | using std::is_array; 23 | using std::is_base_of; 24 | using std::is_base_of_v; 25 | using std::is_function; 26 | using std::is_integral; 27 | using std::is_integral_v; 28 | using std::is_same; 29 | using std::is_same_v; 30 | using std::is_signed; 31 | using std::is_signed_v; 32 | using std::is_unsigned; 33 | using std::is_unsigned_v; 34 | using std::move; 35 | using std::nullptr_t; 36 | using std::remove_extent; 37 | using std::remove_reference; 38 | using std::swap; 39 | using std::true_type; 40 | } 41 | 42 | namespace std { 43 | #if INTMAX_BITS >= 128 44 | template<> struct is_signed : true_type {}; 45 | template<> struct is_unsigned : true_type {}; 46 | #endif 47 | } 48 | -------------------------------------------------------------------------------- /encode/wav.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Encode { 4 | 5 | struct WAV { 6 | static auto stereo_16bit(const string& filename, array_view left, array_view right, uint frequency) -> bool { 7 | if(left.size() != right.size()) return false; 8 | static uint channels = 2; 9 | static uint bits = 16; 10 | static uint samples = left.size(); 11 | 12 | file_buffer fp; 13 | if(!fp.open(filename, file::mode::write)) return false; 14 | 15 | fp.write('R'); 16 | fp.write('I'); 17 | fp.write('F'); 18 | fp.write('F'); 19 | fp.writel(4 + (8 + 16) + (8 + samples * 4), 4); 20 | 21 | fp.write('W'); 22 | fp.write('A'); 23 | fp.write('V'); 24 | fp.write('E'); 25 | 26 | fp.write('f'); 27 | fp.write('m'); 28 | fp.write('t'); 29 | fp.write(' '); 30 | fp.writel(16, 4); 31 | fp.writel(1, 2); 32 | fp.writel(channels, 2); 33 | fp.writel(frequency, 4); 34 | fp.writel(frequency * channels * bits, 4); 35 | fp.writel(channels * bits, 2); 36 | fp.writel(bits, 2); 37 | 38 | fp.write('d'); 39 | fp.write('a'); 40 | fp.write('t'); 41 | fp.write('a'); 42 | fp.writel(samples * 4, 4); 43 | for(uint sample : range(samples)) { 44 | fp.writel(left[sample], 2); 45 | fp.writel(right[sample], 2); 46 | } 47 | 48 | return true; 49 | } 50 | }; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /encode/base.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //required bytes: ceil(bits / log2(base)) 4 | //base57 => 128=22, 256=44, 512=88 5 | //base62 => 128=22, 256=43, 512=86 6 | //base64 => 128=22, 256=43, 512=86 7 | 8 | #include 9 | 10 | namespace nall::Encode { 11 | 12 | template inline auto Base(T value) -> string { 13 | static const string format = 14 | Bits == 2 ? "01" 15 | : Bits == 8 ? "01234567" 16 | : Bits == 10 ? "0123456789" 17 | : Bits == 16 ? "0123456789abcdef" 18 | : Bits == 32 ? "0123456789abcdefghijklmnopqrstuv" 19 | : Bits == 34 ? "023456789abcdefghijkmnopqrstuvwxyz" //1l 20 | : Bits == 36 ? "0123456789abcdefghijklmnopqrstuvwxyz" 21 | : Bits == 57 ? "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" //01IOl 22 | : Bits == 62 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 23 | : Bits == 64 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{}" 24 | : Bits == 85 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%()+,-.:;=@[]^_`{|}~" //\ "&'*/<>? 25 | : ""; 26 | static const uint size = ceil(sizeof(T) * 8 / log2(Bits)); 27 | 28 | string result; 29 | result.resize(size); 30 | char* data = result.get() + size; 31 | for(auto byte : result) { 32 | *--data = format[value % Bits]; 33 | value /= Bits; 34 | } 35 | return result; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /vector/core.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template vector::vector(const initializer_list& values) { 6 | reserveRight(values.size()); 7 | for(auto& value : values) append(value); 8 | } 9 | 10 | template vector::vector(const vector& source) { 11 | operator=(source); 12 | } 13 | 14 | template vector::vector(vector&& source) { 15 | operator=(move(source)); 16 | } 17 | 18 | template vector::~vector() { 19 | reset(); 20 | } 21 | 22 | template vector::operator bool() const { 23 | return _size; 24 | } 25 | 26 | template vector::operator array_span() { 27 | return {data(), size()}; 28 | } 29 | 30 | template vector::operator array_view() const { 31 | return {data(), size()}; 32 | } 33 | 34 | template template auto vector::capacity() const -> uint64_t { 35 | return (_left + _size + _right) * sizeof(T) / sizeof(Cast); 36 | } 37 | 38 | template template auto vector::size() const -> uint64_t { 39 | return _size * sizeof(T) / sizeof(Cast); 40 | } 41 | 42 | template template auto vector::data() -> Cast* { 43 | return (Cast*)_pool; 44 | } 45 | 46 | template template auto vector::data() const -> const Cast* { 47 | return (const Cast*)_pool; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /hash/hash.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | //cannot use constructor inheritance due to needing to call virtual reset(); 8 | //instead, define a macro to reduce boilerplate code in every Hash subclass 9 | #define nallHash(Name) \ 10 | Name() { reset(); } \ 11 | Name(const void* data, uint64_t size) : Name() { input(data, size); } \ 12 | Name(const vector& data) : Name() { input(data); } \ 13 | Name(const string& data) : Name() { input(data); } \ 14 | using Hash::input; \ 15 | 16 | namespace nall::Hash { 17 | 18 | struct Hash { 19 | virtual auto reset() -> void = 0; 20 | virtual auto input(uint8_t data) -> void = 0; 21 | virtual auto output() const -> vector = 0; 22 | 23 | auto input(array_view data) -> void { 24 | for(auto byte : data) input(byte); 25 | } 26 | 27 | auto input(const void* data, uint64_t size) -> void { 28 | auto p = (const uint8_t*)data; 29 | while(size--) input(*p++); 30 | } 31 | 32 | auto input(const vector& data) -> void { 33 | for(auto byte : data) input(byte); 34 | } 35 | 36 | auto input(const string& data) -> void { 37 | for(auto byte : data) input(byte); 38 | } 39 | 40 | auto digest() const -> string { 41 | string result; 42 | for(auto n : output()) result.append(hex(n, 2L)); 43 | return result; 44 | } 45 | }; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /string/convert.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline auto string::downcase() -> string& { 6 | char* p = get(); 7 | for(uint n = 0; n < size(); n++) { 8 | if(p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20; 9 | } 10 | return *this; 11 | } 12 | 13 | inline auto string::qdowncase() -> string& { 14 | char* p = get(); 15 | for(uint n = 0, quoted = 0; n < size(); n++) { 16 | if(p[n] == '\"') quoted ^= 1; 17 | if(!quoted && p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20; 18 | } 19 | return *this; 20 | } 21 | 22 | inline auto string::upcase() -> string& { 23 | char* p = get(); 24 | for(uint n = 0; n < size(); n++) { 25 | if(p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20; 26 | } 27 | return *this; 28 | } 29 | 30 | inline auto string::qupcase() -> string& { 31 | char* p = get(); 32 | for(uint n = 0, quoted = 0; n < size(); n++) { 33 | if(p[n] == '\"') quoted ^= 1; 34 | if(!quoted && p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20; 35 | } 36 | return *this; 37 | } 38 | 39 | inline auto string::transform(string_view from, string_view to) -> string& { 40 | if(from.size() != to.size() || from.size() == 0) return *this; //patterns must be the same length 41 | char* p = get(); 42 | for(uint n = 0; n < size(); n++) { 43 | for(uint s = 0; s < from.size(); s++) { 44 | if(p[n] == from[s]) { 45 | p[n] = to[s]; 46 | break; 47 | } 48 | } 49 | } 50 | return *this; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /http/client.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall::HTTP { 6 | 7 | struct Client : Role { 8 | auto open(const string& hostname, uint port = 80) -> bool; 9 | auto upload(const Request& request) -> bool; 10 | auto download(const Request& request) -> Response; 11 | auto close() -> void; 12 | ~Client() { close(); } 13 | 14 | private: 15 | int fd = -1; 16 | addrinfo* info = nullptr; 17 | }; 18 | 19 | inline auto Client::open(const string& hostname, uint port) -> bool { 20 | addrinfo hint = {0}; 21 | hint.ai_family = AF_UNSPEC; 22 | hint.ai_socktype = SOCK_STREAM; 23 | hint.ai_flags = AI_ADDRCONFIG; 24 | 25 | if(getaddrinfo(hostname, string{port}, &hint, &info) != 0) return close(), false; 26 | 27 | fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol); 28 | if(fd < 0) return close(), false; 29 | 30 | if(connect(fd, info->ai_addr, info->ai_addrlen) < 0) return close(), false; 31 | return true; 32 | } 33 | 34 | inline auto Client::upload(const Request& request) -> bool { 35 | return Role::upload(fd, request); 36 | } 37 | 38 | inline auto Client::download(const Request& request) -> Response { 39 | Response response(request); 40 | Role::download(fd, response); 41 | return response; 42 | } 43 | 44 | inline auto Client::close() -> void { 45 | if(fd) { 46 | ::close(fd); 47 | fd = -1; 48 | } 49 | 50 | if(info) { 51 | freeaddrinfo(info); 52 | info = nullptr; 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /encode/rle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Encode { 4 | 5 | template //S = word size; M = match length 6 | inline auto RLE(array_view input) -> vector { 7 | vector output; 8 | for(uint byte : range(8)) output.append(input.size() >> byte * 8); 9 | 10 | uint base = 0; 11 | uint skip = 0; 12 | 13 | auto load = [&](uint offset) -> uint8_t { 14 | return input(offset); 15 | }; 16 | 17 | auto read = [&](uint offset) -> uint64_t { 18 | uint64_t value = 0; 19 | for(uint byte : range(S)) value |= load(offset + byte) << byte * 8; 20 | return value; 21 | }; 22 | 23 | auto write = [&](uint64_t value) -> void { 24 | for(uint byte : range(S)) output.append(value >> byte * 8); 25 | }; 26 | 27 | auto flush = [&] { 28 | output.append(skip - 1); 29 | do { 30 | write(read(base)); 31 | base += S; 32 | } while(--skip); 33 | }; 34 | 35 | while(base + S * skip < input.size()) { 36 | uint same = 1; 37 | for(uint offset = base + S * (skip + 1); offset < input.size(); offset += S) { 38 | if(read(offset) != read(base + S * skip)) break; 39 | if(++same == 127 + M) break; 40 | } 41 | 42 | if(same < M) { 43 | if(++skip == 128) flush(); 44 | } else { 45 | if(skip) flush(); 46 | output.append(128 | same - M); 47 | write(read(base)); 48 | base += S * same; 49 | } 50 | } 51 | if(skip) flush(); 52 | 53 | return output; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /adaptive-array.hpp: -------------------------------------------------------------------------------- 1 | //deprecated 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | namespace nall { 9 | 10 | template 11 | struct adaptive_array { 12 | auto capacity() const -> uint { return Capacity; } 13 | auto size() const -> uint { return _size; } 14 | 15 | auto reset() -> void { 16 | for(uint n : range(_size)) _pool.t[n].~T(); 17 | _size = 0; 18 | } 19 | 20 | auto operator[](uint index) -> T& { 21 | #ifdef DEBUG 22 | struct out_of_bounds {}; 23 | if(index >= Capacity) throw out_of_bounds{}; 24 | #endif 25 | return _pool.t[index]; 26 | } 27 | 28 | auto operator[](uint index) const -> const T& { 29 | #ifdef DEBUG 30 | struct out_of_bounds {}; 31 | if(index >= Capacity) throw out_of_bounds{}; 32 | #endif 33 | return _pool.t[index]; 34 | } 35 | 36 | auto append() -> T& { 37 | new(_pool.t + _size) T; 38 | return _pool.t[_size++]; 39 | } 40 | 41 | auto append(const T& value) -> void { 42 | new(_pool.t + _size++) T(value); 43 | } 44 | 45 | auto append(T&& value) -> void { 46 | new(_pool.t + _size++) T(move(value)); 47 | } 48 | 49 | auto begin() { return &_pool.t[0]; } 50 | auto end() { return &_pool.t[_size]; } 51 | 52 | auto begin() const { return &_pool.t[0]; } 53 | auto end() const { return &_pool.t[_size]; } 54 | 55 | private: 56 | union U { 57 | U() {} 58 | ~U() {} 59 | T t[Capacity]; 60 | } _pool; 61 | uint _size = 0; 62 | }; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /primitives/real.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template struct Real { 6 | static_assert(Precision == 32 || Precision == 64); 7 | static constexpr auto bits() -> uint { return Precision; } 8 | using ftype = 9 | conditional_t>; 12 | 13 | Real() : data(0.0) {} 14 | template Real(Real value) : data((ftype)value) {} 15 | template Real(const T& value) : data((ftype)value) {} 16 | explicit Real(const char* value) : data((ftype)toReal(value)) {} 17 | 18 | operator ftype() const { return data; } 19 | 20 | auto operator++(int) { auto value = *this; ++data; return value; } 21 | auto operator--(int) { auto value = *this; --data; return value; } 22 | 23 | auto& operator++() { data++; return *this; } 24 | auto& operator--() { data--; return *this; } 25 | 26 | template auto& operator =(const T& value) { data = value; return *this; } 27 | template auto& operator*=(const T& value) { data = data * value; return *this; } 28 | template auto& operator/=(const T& value) { data = data / value; return *this; } 29 | template auto& operator%=(const T& value) { data = data % value; return *this; } 30 | template auto& operator+=(const T& value) { data = data + value; return *this; } 31 | template auto& operator-=(const T& value) { data = data - value; return *this; } 32 | 33 | auto serialize(serializer& s) { s(data); } 34 | 35 | private: 36 | ftype data; 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /string/split.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template 6 | inline auto vector::_split(string_view source, string_view find, long limit) -> type& { 7 | reset(); 8 | if(limit <= 0 || find.size() == 0) return *this; 9 | 10 | const char* p = source.data(); 11 | int size = source.size(); 12 | int base = 0; 13 | int matches = 0; 14 | 15 | for(int n = 0, quoted = 0; n <= size - (int)find.size();) { 16 | if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } 17 | if(string::_compare(p + n, size - n, find.data(), find.size())) { n++; continue; } 18 | if(matches >= limit) break; 19 | 20 | string& s = operator()(matches); 21 | s.resize(n - base); 22 | memory::copy(s.get(), p + base, n - base); 23 | 24 | n += find.size(); 25 | base = n; 26 | matches++; 27 | } 28 | 29 | string& s = operator()(matches); 30 | s.resize(size - base); 31 | memory::copy(s.get(), p + base, size - base); 32 | 33 | return *this; 34 | } 35 | 36 | inline auto string::split(string_view on, long limit) const -> vector { return vector()._split<0, 0>(*this, on, limit); } 37 | inline auto string::isplit(string_view on, long limit) const -> vector { return vector()._split<1, 0>(*this, on, limit); } 38 | inline auto string::qsplit(string_view on, long limit) const -> vector { return vector()._split<0, 1>(*this, on, limit); } 39 | inline auto string::iqsplit(string_view on, long limit) const -> vector { return vector()._split<1, 1>(*this, on, limit); } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /vector/utility.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template auto vector::fill(const T& value) -> void { 6 | for(uint64_t n : range(size())) _pool[n] = value; 7 | } 8 | 9 | template auto vector::sort(const function& comparator) -> void { 10 | nall::sort(_pool, _size, comparator); 11 | } 12 | 13 | template auto vector::reverse() -> void { 14 | vector reversed; 15 | for(uint64_t n : range(size())) reversed.prepend(_pool[n]); 16 | operator=(move(reversed)); 17 | } 18 | 19 | template auto vector::find(const function& comparator) -> maybe { 20 | for(uint64_t n : range(size())) if(comparator(_pool[n])) return n; 21 | return nothing; 22 | } 23 | 24 | template auto vector::find(const T& value) const -> maybe { 25 | for(uint64_t n : range(size())) if(_pool[n] == value) return n; 26 | return nothing; 27 | } 28 | 29 | template auto vector::findSorted(const T& value) const -> maybe { 30 | int64_t l = 0, r = size() - 1; 31 | while(l <= r) { 32 | int64_t m = l + (r - l >> 1); 33 | if(value == _pool[m]) return m; 34 | value < _pool[m] ? r = m - 1 : l = m + 1; 35 | } 36 | return nothing; 37 | } 38 | 39 | template auto vector::foreach(const function& callback) -> void { 40 | for(uint64_t n : range(size())) callback(_pool[n]); 41 | } 42 | 43 | template auto vector::foreach(const function& callback) -> void { 44 | for(uint64_t n : range(size())) callback(n, _pool[n]); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /main.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace nall { 8 | auto main(Arguments arguments) -> void; 9 | 10 | auto main(int argc, char** argv) -> int { 11 | #if defined(PLATFORM_WINDOWS) 12 | CoInitialize(0); 13 | WSAData wsaData{0}; 14 | WSAStartup(MAKEWORD(2, 2), &wsaData); 15 | _setmode(_fileno(stdin ), O_BINARY); 16 | _setmode(_fileno(stdout), O_BINARY); 17 | _setmode(_fileno(stderr), O_BINARY); 18 | #endif 19 | 20 | main(move(Arguments{argc, argv})); 21 | 22 | //when a program is running, input on the terminal queues in stdin 23 | //when terminating the program, the shell proceeds to try and execute all stdin data 24 | //this is annoying behavior: this code tries to minimize the impact as much as it can 25 | //we can flush all of stdin up to the last line feed, preventing spurious commands from executing 26 | //however, even with setvbuf(_IONBF), we can't stop the last line from echoing to the terminal 27 | #if !defined(PLATFORM_WINDOWS) 28 | auto flags = fcntl(fileno(stdin), F_GETFL, 0); 29 | fcntl(fileno(stdin), F_SETFL, flags | O_NONBLOCK); //don't allow read() to block when empty 30 | char buffer[4096], data = false; 31 | while(read(fileno(stdin), buffer, sizeof(buffer)) > 0) data = true; 32 | fcntl(fileno(stdin), F_SETFL, flags); //restore original flags for the terminal 33 | if(data) putchar('\r'); //ensures PS1 is printed at the start of the line 34 | #endif 35 | 36 | return EXIT_SUCCESS; 37 | } 38 | } 39 | 40 | auto main(int argc, char** argv) -> int { 41 | return nall::main(argc, argv); 42 | } 43 | -------------------------------------------------------------------------------- /string/vector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template inline auto vector::append(const string& data, P&&... p) -> type& { 6 | vector_base::append(data); 7 | append(forward

(p)...); 8 | return *this; 9 | } 10 | 11 | inline auto vector::append() -> type& { 12 | return *this; 13 | } 14 | 15 | inline auto vector::isort() -> type& { 16 | sort([](const string& x, const string& y) { 17 | return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0; 18 | }); 19 | return *this; 20 | } 21 | 22 | inline auto vector::find(string_view source) const -> maybe { 23 | for(uint n = 0; n < size(); n++) { 24 | if(operator[](n).equals(source)) return n; 25 | } 26 | return {}; 27 | } 28 | 29 | inline auto vector::ifind(string_view source) const -> maybe { 30 | for(uint n = 0; n < size(); n++) { 31 | if(operator[](n).iequals(source)) return n; 32 | } 33 | return {}; 34 | } 35 | 36 | inline auto vector::match(string_view pattern) const -> vector { 37 | vector result; 38 | for(uint n = 0; n < size(); n++) { 39 | if(operator[](n).match(pattern)) result.append(operator[](n)); 40 | } 41 | return result; 42 | } 43 | 44 | inline auto vector::merge(string_view separator) const -> string { 45 | string output; 46 | for(uint n = 0; n < size(); n++) { 47 | output.append(operator[](n)); 48 | if(n < size() - 1) output.append(separator.data()); 49 | } 50 | return output; 51 | } 52 | 53 | inline auto vector::strip() -> type& { 54 | for(uint n = 0; n < size(); n++) { 55 | operator[](n).strip(); 56 | } 57 | return *this; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /elliptic-curve/curve25519.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(EC_REFERENCE) 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | namespace nall::EllipticCurve { 10 | 11 | struct Curve25519 { 12 | auto sharedKey(uint256_t secretKey, uint256_t basepoint = 9) const -> uint256_t { 13 | secretKey &= (1_u256 << 254) - 8; 14 | secretKey |= (1_u256 << 254); 15 | basepoint &= ~0_u256 >> 1; 16 | 17 | point p = scalarMultiply(basepoint % P, secretKey); 18 | field k = p.x * reciprocal(p.z); 19 | return k(); 20 | } 21 | 22 | private: 23 | using field = Modulo25519; 24 | struct point { field x, z; }; 25 | const BarrettReduction<256> P = BarrettReduction<256>{EllipticCurve::P}; 26 | 27 | auto montgomeryDouble(point p) const -> point { 28 | field a = square(p.x + p.z); 29 | field b = square(p.x - p.z); 30 | field c = a - b; 31 | field d = a + c * 121665; 32 | return {a * b, c * d}; 33 | } 34 | 35 | auto montgomeryAdd(point p, point q, field b) const -> point { 36 | return { 37 | square(p.x * q.x - p.z * q.z), 38 | square(p.x * q.z - p.z * q.x) * b 39 | }; 40 | } 41 | 42 | auto scalarMultiply(field b, uint256_t exponent) const -> point { 43 | point p{1, 0}, q{b, 1}; 44 | for(uint bit : reverse(range(255))) { 45 | bool condition = exponent >> bit & 1; 46 | cswap(condition, p.x, q.x); 47 | cswap(condition, p.z, q.z); 48 | q = montgomeryAdd(p, q, b); 49 | p = montgomeryDouble(p); 50 | cswap(condition, p.x, q.x); 51 | cswap(condition, p.z, q.z); 52 | } 53 | return p; 54 | } 55 | }; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /range.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | struct range_t { 6 | struct iterator { 7 | iterator(int64_t position, int64_t step = 0) : position(position), step(step) {} 8 | auto operator*() const -> int64_t { return position; } 9 | auto operator!=(const iterator& source) const -> bool { return step > 0 ? position < source.position : position > source.position; } 10 | auto operator++() -> iterator& { position += step; return *this; } 11 | 12 | private: 13 | int64_t position; 14 | const int64_t step; 15 | }; 16 | 17 | struct reverse_iterator { 18 | reverse_iterator(int64_t position, int64_t step = 0) : position(position), step(step) {} 19 | auto operator*() const -> int64_t { return position; } 20 | auto operator!=(const reverse_iterator& source) const -> bool { return step > 0 ? position > source.position : position < source.position; } 21 | auto operator++() -> reverse_iterator& { position -= step; return *this; } 22 | 23 | private: 24 | int64_t position; 25 | const int64_t step; 26 | }; 27 | 28 | auto begin() const -> iterator { return {origin, stride}; } 29 | auto end() const -> iterator { return {target}; } 30 | 31 | auto rbegin() const -> reverse_iterator { return {target - stride, stride}; } 32 | auto rend() const -> reverse_iterator { return {origin - stride}; } 33 | 34 | int64_t origin; 35 | int64_t target; 36 | int64_t stride; 37 | }; 38 | 39 | inline auto range(int64_t size) { 40 | return range_t{0, size, 1}; 41 | } 42 | 43 | inline auto range(int64_t offset, int64_t size) { 44 | return range_t{offset, size, 1}; 45 | } 46 | 47 | inline auto range(int64_t offset, int64_t size, int64_t step) { 48 | return range_t{offset, size, step}; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /encode/bmp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Encode { 4 | 5 | struct BMP { 6 | static auto create(const string& filename, const void* data, uint pitch, uint width, uint height, bool alpha) -> bool { 7 | auto fp = file::open(filename, file::mode::write); 8 | if(!fp) return false; 9 | 10 | uint bitsPerPixel = alpha ? 32 : 24; 11 | uint bytesPerPixel = bitsPerPixel / 8; 12 | uint alignedWidth = width * bytesPerPixel; 13 | uint paddingLength = 0; 14 | uint imageSize = alignedWidth * height; 15 | uint fileSize = 0x36 + imageSize; 16 | while(alignedWidth % 4) alignedWidth++, paddingLength++; 17 | 18 | fp.writel(0x4d42, 2); //signature 19 | fp.writel(fileSize, 4); //file size 20 | fp.writel(0, 2); //reserved 21 | fp.writel(0, 2); //reserved 22 | fp.writel(0x36, 4); //offset 23 | 24 | fp.writel(40, 4); //DIB size 25 | fp.writel(width, 4); //width 26 | fp.writel(-height, 4); //height 27 | fp.writel(1, 2); //color planes 28 | fp.writel(bitsPerPixel, 2); //bits per pixel 29 | fp.writel(0, 4); //compression method (BI_RGB) 30 | fp.writel(imageSize, 4); //image data size 31 | fp.writel(3780, 4); //horizontal resolution 32 | fp.writel(3780, 4); //vertical resolution 33 | fp.writel(0, 4); //palette size 34 | fp.writel(0, 4); //important color count 35 | 36 | pitch >>= 2; 37 | for(auto y : range(height)) { 38 | auto p = (const uint32_t*)data + y * pitch; 39 | for(auto x : range(width)) fp.writel(*p++, bytesPerPixel); 40 | if(paddingLength) fp.writel(0, paddingLength); 41 | } 42 | 43 | return true; 44 | } 45 | }; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /arithmetic/unsigned.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template::value>> 6 | inline auto upper(T value) -> T { 7 | return value >> sizeof(T) * 4; 8 | } 9 | 10 | template::value>> 11 | inline auto lower(T value) -> T { 12 | static const T Mask = ~T(0) >> sizeof(T) * 4; 13 | return value & Mask; 14 | } 15 | 16 | template::value>, enable_if_t::value>> 17 | inline auto mul(T lhs, U rhs) -> uintmax { 18 | return lhs * rhs; 19 | } 20 | 21 | template::value>> 22 | inline auto square(T value) -> uintmax { 23 | return value * value; 24 | } 25 | 26 | template 27 | inline auto rol(T lhs, U rhs, enable_if_t::value>* = 0) -> T { 28 | return lhs << rhs | lhs >> sizeof(T) * 8 - rhs; 29 | } 30 | 31 | template 32 | inline auto ror(T lhs, U rhs, enable_if_t::value>* = 0) -> T { 33 | return lhs >> rhs | lhs << sizeof(T) * 8 - rhs; 34 | } 35 | 36 | #if INTMAX_BITS >= 128 37 | inline auto operator"" _u128(const char* s) -> uint128_t { 38 | uint128_t p = 0; 39 | if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { 40 | s += 2; 41 | while(*s) { 42 | auto c = *s++; 43 | if(c == '\''); 44 | else if(c >= '0' && c <= '9') p = (p << 4) + (c - '0'); 45 | else if(c >= 'a' && c <= 'f') p = (p << 4) + (c - 'a' + 10); 46 | else if(c >= 'A' && c <= 'F') p = (p << 4) + (c - 'A' + 10); 47 | else break; 48 | } 49 | } else { 50 | while(*s) { 51 | auto c = *s++; 52 | if(c == '\''); 53 | else if(c >= '0' && c <= '9') p = (p << 3) + (p << 1) + (c - '0'); 54 | else break; 55 | } 56 | } 57 | return p; 58 | } 59 | #endif 60 | 61 | } 62 | -------------------------------------------------------------------------------- /interpolation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | struct Interpolation { 6 | static inline auto Nearest(double mu, double a, double b, double c, double d) -> double { 7 | return (mu <= 0.5 ? b : c); 8 | } 9 | 10 | static inline auto Sublinear(double mu, double a, double b, double c, double d) -> double { 11 | mu = ((mu - 0.5) * 2.0) + 0.5; 12 | if(mu < 0) mu = 0; 13 | if(mu > 1) mu = 1; 14 | return b * (1.0 - mu) + c * mu; 15 | } 16 | 17 | static inline auto Linear(double mu, double a, double b, double c, double d) -> double { 18 | return b * (1.0 - mu) + c * mu; 19 | } 20 | 21 | static inline auto Cosine(double mu, double a, double b, double c, double d) -> double { 22 | mu = (1.0 - cos(mu * Math::Pi)) / 2.0; 23 | return b * (1.0 - mu) + c * mu; 24 | } 25 | 26 | static inline auto Cubic(double mu, double a, double b, double c, double d) -> double { 27 | double A = d - c - a + b; 28 | double B = a - b - A; 29 | double C = c - a; 30 | double D = b; 31 | return A * (mu * mu * mu) + B * (mu * mu) + C * mu + D; 32 | } 33 | 34 | static inline auto Hermite(double mu1, double a, double b, double c, double d) -> double { 35 | const double tension = 0.0; //-1 = low, 0 = normal, +1 = high 36 | const double bias = 0.0; //-1 = left, 0 = even, +1 = right 37 | double mu2, mu3, m0, m1, a0, a1, a2, a3; 38 | 39 | mu2 = mu1 * mu1; 40 | mu3 = mu2 * mu1; 41 | 42 | m0 = (b - a) * (1.0 + bias) * (1.0 - tension) / 2.0; 43 | m0 += (c - b) * (1.0 - bias) * (1.0 - tension) / 2.0; 44 | m1 = (c - b) * (1.0 + bias) * (1.0 - tension) / 2.0; 45 | m1 += (d - c) * (1.0 - bias) * (1.0 - tension) / 2.0; 46 | 47 | a0 = +2 * mu3 - 3 * mu2 + 1; 48 | a1 = mu3 - 2 * mu2 + mu1; 49 | a2 = mu3 - mu2; 50 | a3 = -2 * mu3 + 3 * mu2; 51 | 52 | return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); 53 | } 54 | }; 55 | 56 | } 57 | -------------------------------------------------------------------------------- /decode/gzip.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace nall::Decode { 7 | 8 | struct GZIP { 9 | inline ~GZIP(); 10 | 11 | inline auto decompress(const string& filename) -> bool; 12 | inline auto decompress(const uint8_t* data, uint size) -> bool; 13 | 14 | string filename; 15 | uint8_t* data = nullptr; 16 | uint size = 0; 17 | }; 18 | 19 | GZIP::~GZIP() { 20 | if(data) delete[] data; 21 | } 22 | 23 | auto GZIP::decompress(const string& filename) -> bool { 24 | if(auto memory = file::read(filename)) { 25 | return decompress(memory.data(), memory.size()); 26 | } 27 | return false; 28 | } 29 | 30 | auto GZIP::decompress(const uint8_t* data, uint size) -> bool { 31 | if(size < 18) return false; 32 | if(data[0] != 0x1f) return false; 33 | if(data[1] != 0x8b) return false; 34 | uint cm = data[2]; 35 | uint flg = data[3]; 36 | uint mtime = data[4]; 37 | mtime |= data[5] << 8; 38 | mtime |= data[6] << 16; 39 | mtime |= data[7] << 24; 40 | uint xfl = data[8]; 41 | uint os = data[9]; 42 | uint p = 10; 43 | uint isize = data[size - 4]; 44 | isize |= data[size - 3] << 8; 45 | isize |= data[size - 2] << 16; 46 | isize |= data[size - 1] << 24; 47 | filename = ""; 48 | 49 | if(flg & 0x04) { //FEXTRA 50 | uint xlen = data[p + 0]; 51 | xlen |= data[p + 1] << 8; 52 | p += 2 + xlen; 53 | } 54 | 55 | if(flg & 0x08) { //FNAME 56 | char buffer[PATH_MAX]; 57 | for(uint n = 0; n < PATH_MAX; n++, p++) { 58 | buffer[n] = data[p]; 59 | if(data[p] == 0) break; 60 | } 61 | if(data[p++]) return false; 62 | filename = buffer; 63 | } 64 | 65 | if(flg & 0x10) { //FCOMMENT 66 | while(data[p++]); 67 | } 68 | 69 | if(flg & 0x02) { //FHCRC 70 | p += 2; 71 | } 72 | 73 | this->size = isize; 74 | this->data = new uint8_t[this->size]; 75 | return inflate(this->data, this->size, data + p, size - p - 8); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /encode/base64.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Encode { 4 | 5 | inline auto Base64(const void* vdata, uint size, const string& format = "MIME") -> string { 6 | static bool initialized = false; 7 | static char lookup[65] = {0}; 8 | if(!initialized) { 9 | initialized = true; 10 | for(uint n : range(26)) lookup[n + 0] = 'A' + n; 11 | for(uint n : range(26)) lookup[n + 26] = 'a' + n; 12 | for(uint n : range(10)) lookup[n + 52] = '0' + n; 13 | } 14 | 15 | if(format == "MIME") { 16 | lookup[62] = '+'; 17 | lookup[63] = '/'; 18 | lookup[64] = '='; 19 | } else if(format == "URI") { 20 | lookup[62] = '-'; 21 | lookup[63] = '_'; 22 | lookup[64] = 0; 23 | } else return ""; 24 | 25 | auto data = (const uint8_t*)vdata; 26 | uint overflow = (3 - (size % 3)) % 3; //bytes to round to nearest multiple of 3 27 | string result; 28 | uint8_t buffer; 29 | for(uint n : range(size)) { 30 | switch(n % 3) { 31 | case 0: 32 | buffer = data[n] >> 2; 33 | result.append(lookup[buffer]); 34 | buffer = (data[n] & 3) << 4; 35 | break; 36 | 37 | case 1: 38 | buffer |= data[n] >> 4; 39 | result.append(lookup[buffer]); 40 | buffer = (data[n] & 15) << 2; 41 | break; 42 | 43 | case 2: 44 | buffer |= data[n] >> 6; 45 | result.append(lookup[buffer]); 46 | buffer = (data[n] & 63); 47 | result.append(lookup[buffer]); 48 | break; 49 | } 50 | } 51 | 52 | if(overflow) result.append(lookup[buffer]); 53 | if(lookup[64]) { 54 | while(result.size() % 4) result.append(lookup[64]); 55 | } 56 | 57 | return result; 58 | } 59 | 60 | inline auto Base64(const vector& buffer, const string& format = "MIME") -> string { 61 | return Base64(buffer.data(), buffer.size(), format); 62 | } 63 | 64 | inline auto Base64(const string& text, const string& format = "MIME") -> string { 65 | return Base64(text.data(), text.size(), format); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /cd/edc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //error detection code 4 | 5 | namespace nall::CD::EDC { 6 | 7 | //polynomial(x) = (x^16 + x^15 + x^2 + 1) * (x^16 + x^2 + x + 1) 8 | inline auto polynomial(uint8_t x) -> uint32_t { 9 | static uint32_t lookup[256]{}; 10 | static bool once = false; 11 | if(!once) { once = true; 12 | for(uint n : range(256)) { 13 | uint32_t edc = n; 14 | for(uint b : range(8)) edc = edc >> 1 ^ (edc & 1 ? 0xd8018001 : 0); 15 | lookup[n] = edc; 16 | } 17 | } 18 | return lookup[x]; 19 | } 20 | 21 | // 22 | 23 | inline auto create(array_view input) -> uint32_t { 24 | uint32_t sum = 0; 25 | for(auto& byte : input) sum = sum >> 8 ^ polynomial(sum ^ byte); 26 | return sum; 27 | } 28 | 29 | inline auto create(array_view input, array_span output) -> bool { 30 | if(output.size() != 4) return false; 31 | auto sum = create(input); 32 | output[0u] = sum >> 0; 33 | output[1u] = sum >> 8; 34 | output[2u] = sum >> 16; 35 | output[3u] = sum >> 24; 36 | return true; 37 | } 38 | 39 | inline auto createMode1(array_span sector) -> bool { 40 | if(sector.size() != 2352) return false; 41 | return create({sector, 2064}, {sector + 2064, 4}); 42 | } 43 | 44 | // 45 | 46 | inline auto verify(array_view input, uint32_t edc) -> bool { 47 | return edc == create(input); 48 | } 49 | 50 | inline auto verify(array_view input, array_view compare) -> bool { 51 | if(compare.size() != 4) return false; 52 | auto sum = create(input); 53 | if(compare[0u] != uint8_t(sum >> 0)) return false; 54 | if(compare[1u] != uint8_t(sum >> 8)) return false; 55 | if(compare[2u] != uint8_t(sum >> 16)) return false; 56 | if(compare[3u] != uint8_t(sum >> 24)) return false; 57 | return true; 58 | } 59 | 60 | inline auto verifyMode1(array_view sector) -> bool { 61 | if(sector.size() != 2352) return false; 62 | return verify({sector, 2064}, {sector + 2064, 4}); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /endian.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #if defined(ENDIAN_LSB) 6 | //little-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x04030201 7 | #define order_lsb1(a) a 8 | #define order_lsb2(a,b) a,b 9 | #define order_lsb3(a,b,c) a,b,c 10 | #define order_lsb4(a,b,c,d) a,b,c,d 11 | #define order_lsb5(a,b,c,d,e) a,b,c,d,e 12 | #define order_lsb6(a,b,c,d,e,f) a,b,c,d,e,f 13 | #define order_lsb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g 14 | #define order_lsb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h 15 | #define order_msb1(a) a 16 | #define order_msb2(a,b) b,a 17 | #define order_msb3(a,b,c) c,b,a 18 | #define order_msb4(a,b,c,d) d,c,b,a 19 | #define order_msb5(a,b,c,d,e) e,d,c,b,a 20 | #define order_msb6(a,b,c,d,e,f) f,e,d,c,b,a 21 | #define order_msb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a 22 | #define order_msb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a 23 | #elif defined(ENDIAN_MSB) 24 | //big-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x01020304 25 | #define order_lsb1(a) a 26 | #define order_lsb2(a,b) b,a 27 | #define order_lsb3(a,b,c) c,b,a 28 | #define order_lsb4(a,b,c,d) d,c,b,a 29 | #define order_lsb5(a,b,c,d,e) e,d,c,b,a 30 | #define order_lsb6(a,b,c,d,e,f) f,e,d,c,b,a 31 | #define order_lsb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a 32 | #define order_lsb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a 33 | #define order_msb1(a) a 34 | #define order_msb2(a,b) a,b 35 | #define order_msb3(a,b,c) a,b,c 36 | #define order_msb4(a,b,c,d) a,b,c,d 37 | #define order_msb5(a,b,c,d,e) a,b,c,d,e 38 | #define order_msb6(a,b,c,d,e,f) a,b,c,d,e,f 39 | #define order_msb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g 40 | #define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h 41 | #else 42 | #error "Unknown endian. Please specify in nall/intrinsics.hpp" 43 | #endif 44 | -------------------------------------------------------------------------------- /vfs/vfs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace nall::vfs { 7 | 8 | struct file { 9 | enum class mode : uint { read, write, modify, create }; 10 | enum class index : uint { absolute, relative }; 11 | 12 | virtual ~file() = default; 13 | 14 | virtual auto size() const -> uintmax = 0; 15 | virtual auto offset() const -> uintmax = 0; 16 | 17 | virtual auto seek(intmax offset, index = index::absolute) -> void = 0; 18 | virtual auto read() -> uint8_t = 0; 19 | virtual auto write(uint8_t data) -> void = 0; 20 | virtual auto flush() -> void {} 21 | 22 | auto end() const -> bool { 23 | return offset() >= size(); 24 | } 25 | 26 | auto read(void* vdata, uintmax bytes) -> void { 27 | auto data = (uint8_t*)vdata; 28 | while(bytes--) *data++ = read(); 29 | } 30 | 31 | auto readl(uint bytes) -> uintmax { 32 | uintmax data = 0; 33 | for(auto n : range(bytes)) data |= (uintmax)read() << n * 8; 34 | return data; 35 | } 36 | 37 | auto readm(uint bytes) -> uintmax { 38 | uintmax data = 0; 39 | for(auto n : range(bytes)) data = data << 8 | read(); 40 | return data; 41 | } 42 | 43 | auto reads() -> string { 44 | string s; 45 | s.resize(size()); 46 | read(s.get(), s.size()); 47 | return s; 48 | } 49 | 50 | auto write(const void* vdata, uintmax bytes) -> void { 51 | auto data = (const uint8_t*)vdata; 52 | while(bytes--) write(*data++); 53 | } 54 | 55 | auto writel(uintmax data, uint bytes) -> void { 56 | for(auto n : range(bytes)) write(data), data >>= 8; 57 | } 58 | 59 | auto writem(uintmax data, uint bytes) -> void { 60 | for(auto n : reverse(range(bytes))) write(data >> n * 8); 61 | } 62 | 63 | auto writes(const string& s) -> void { 64 | write(s.data(), s.size()); 65 | } 66 | }; 67 | 68 | } 69 | 70 | #include 71 | #include 72 | #include 73 | -------------------------------------------------------------------------------- /string/allocator/vector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | vector allocator 5 | sizeof(string) == 16 (amd64) 6 | 7 | utilizes a raw string pointer 8 | always allocates memory onto the heap when string is not empty 9 | 10 | pros: 11 | * potential for in-place resize 12 | * simplicity 13 | 14 | cons: 15 | * always allocates heap memory on (capacity > 0) 16 | * pass-by-value requires heap allocation 17 | 18 | */ 19 | 20 | namespace nall { 21 | 22 | template 23 | inline auto string::get() -> T* { 24 | if(_capacity == 0) reserve(1); 25 | return (T*)_data; 26 | } 27 | 28 | template 29 | inline auto string::data() const -> const T* { 30 | if(_capacity == 0) return (const T*)""; 31 | return (const T*)_data; 32 | } 33 | 34 | inline auto string::reset() -> type& { 35 | if(_data) { memory::free(_data); _data = nullptr; } 36 | _capacity = 0; 37 | _size = 0; 38 | return *this; 39 | } 40 | 41 | inline auto string::reserve(uint capacity) -> type& { 42 | if(capacity > _capacity) { 43 | _capacity = bit::round(capacity + 1) - 1; 44 | _data = memory::resize(_data, _capacity + 1); 45 | _data[_capacity] = 0; 46 | } 47 | return *this; 48 | } 49 | 50 | inline auto string::resize(uint size) -> type& { 51 | reserve(size); 52 | get()[_size = size] = 0; 53 | return *this; 54 | } 55 | 56 | inline auto string::operator=(const string& source) -> type& { 57 | if(&source == this) return *this; 58 | reset(); 59 | _data = memory::allocate(source._size + 1); 60 | _capacity = source._size; 61 | _size = source._size; 62 | memory::copy(_data, source.data(), source.size() + 1); 63 | return *this; 64 | } 65 | 66 | inline auto string::operator=(string&& source) -> type& { 67 | if(&source == this) return *this; 68 | reset(); 69 | _data = source._data; 70 | _capacity = source._capacity; 71 | _size = source._size; 72 | source._data = nullptr; 73 | source._capacity = 0; 74 | source._size = 0; 75 | return *this; 76 | } 77 | 78 | inline string::string() { 79 | _data = nullptr; 80 | _capacity = 0; 81 | _size = 0; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /vfs/memory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace nall::vfs { 7 | 8 | struct memory : file { 9 | ~memory() { delete[] _data; } 10 | 11 | static auto open(const void* data, uintmax size) -> shared_pointer { 12 | auto instance = shared_pointer{new memory}; 13 | instance->_open((const uint8_t*)data, size); 14 | return instance; 15 | } 16 | 17 | static auto open(string location, bool decompress = false) -> shared_pointer { 18 | auto instance = shared_pointer{new memory}; 19 | if(decompress && location.iendsWith(".zip")) { 20 | Decode::ZIP archive; 21 | if(archive.open(location) && archive.file.size() == 1) { 22 | auto memory = archive.extract(archive.file.first()); 23 | instance->_open(memory.data(), memory.size()); 24 | return instance; 25 | } 26 | } 27 | auto memory = nall::file::read(location); 28 | instance->_open(memory.data(), memory.size()); 29 | return instance; 30 | } 31 | 32 | auto data() const -> const uint8_t* { return _data; } 33 | auto size() const -> uintmax override { return _size; } 34 | auto offset() const -> uintmax override { return _offset; } 35 | 36 | auto seek(intmax offset, index mode) -> void override { 37 | if(mode == index::absolute) _offset = (uintmax)offset; 38 | if(mode == index::relative) _offset += (intmax)offset; 39 | } 40 | 41 | auto read() -> uint8_t override { 42 | if(_offset >= _size) return 0x00; 43 | return _data[_offset++]; 44 | } 45 | 46 | auto write(uint8_t data) -> void override { 47 | if(_offset >= _size) return; 48 | _data[_offset++] = data; 49 | } 50 | 51 | private: 52 | memory() = default; 53 | memory(const file&) = delete; 54 | auto operator=(const memory&) -> memory& = delete; 55 | 56 | auto _open(const uint8_t* data, uintmax size) -> void { 57 | _size = size; 58 | _data = new uint8_t[size]; 59 | nall::memory::copy(_data, data, size); 60 | } 61 | 62 | uint8_t* _data = nullptr; 63 | uintmax _size = 0; 64 | uintmax _offset = 0; 65 | }; 66 | 67 | } 68 | -------------------------------------------------------------------------------- /terminal.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall::terminal { 6 | 7 | inline auto escapable() -> bool { 8 | #if defined(PLATFORM_WINDOWS) 9 | //todo: colors are supported by Windows 10+ and with alternate terminals (eg msys) 10 | //disabled for now for compatibility with Windows 7 and 8.1's cmd.exe 11 | return false; 12 | #endif 13 | return true; 14 | } 15 | 16 | namespace color { 17 | 18 | template inline auto black(P&&... p) -> string { 19 | if(!escapable()) return string{forward

(p)...}; 20 | return {"\e[30m", string{forward

(p)...}, "\e[0m"}; 21 | } 22 | 23 | template inline auto blue(P&&... p) -> string { 24 | if(!escapable()) return string{forward

(p)...}; 25 | return {"\e[94m", string{forward

(p)...}, "\e[0m"}; 26 | } 27 | 28 | template inline auto green(P&&... p) -> string { 29 | if(!escapable()) return string{forward

(p)...}; 30 | return {"\e[92m", string{forward

(p)...}, "\e[0m"}; 31 | } 32 | 33 | template inline auto cyan(P&&... p) -> string { 34 | if(!escapable()) return string{forward

(p)...}; 35 | return {"\e[96m", string{forward

(p)...}, "\e[0m"}; 36 | } 37 | 38 | template inline auto red(P&&... p) -> string { 39 | if(!escapable()) return string{forward

(p)...}; 40 | return {"\e[91m", string{forward

(p)...}, "\e[0m"}; 41 | } 42 | 43 | template inline auto magenta(P&&... p) -> string { 44 | if(!escapable()) return string{forward

(p)...}; 45 | return {"\e[95m", string{forward

(p)...}, "\e[0m"}; 46 | } 47 | 48 | template inline auto yellow(P&&... p) -> string { 49 | if(!escapable()) return string{forward

(p)...}; 50 | return {"\e[93m", string{forward

(p)...}, "\e[0m"}; 51 | } 52 | 53 | template inline auto white(P&&... p) -> string { 54 | if(!escapable()) return string{forward

(p)...}; 55 | return {"\e[97m", string{forward

(p)...}, "\e[0m"}; 56 | } 57 | 58 | template inline auto gray(P&&... p) -> string { 59 | if(!escapable()) return string{forward

(p)...}; 60 | return {"\e[37m", string{forward

(p)...}, "\e[0m"}; 61 | } 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /decode/lzsa.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall::Decode { 6 | 7 | inline auto LZSA(array_view input) -> vector { 8 | vector output; 9 | uint index = 0; 10 | 11 | uint size = 0; 12 | for(uint byte : range(8)) size |= *input++ << byte * 8; 13 | output.resize(size); 14 | 15 | auto load = [&]() -> vector { 16 | uint size = 0; 17 | for(uint byte : range(8)) size |= *input++ << byte * 8; 18 | vector buffer; 19 | buffer.reserve(size); 20 | while(size--) buffer.append(*input++); 21 | return buffer; 22 | }; 23 | 24 | auto flags = Decode::Huffman(load()); 25 | auto literals = Decode::Huffman(load()); 26 | auto lengths = Decode::Huffman(load()); 27 | auto offsets = Decode::Huffman(load()); 28 | 29 | auto flagData = flags.data(); 30 | uint byte = 0, bits = 0; 31 | auto flagRead = [&]() -> bool { 32 | if(bits == 0) bits = 8, byte = *flagData++; 33 | return byte >> --bits & 1; 34 | }; 35 | 36 | auto literalData = literals.data(); 37 | auto literalRead = [&]() -> uint8_t { 38 | return *literalData++; 39 | }; 40 | 41 | auto lengthData = lengths.data(); 42 | auto lengthRead = [&]() -> uint64_t { 43 | uint byte = *lengthData++, bytes = 1; 44 | while(!(byte & 1)) byte >>= 1, bytes++; 45 | uint length = byte >> 1, shift = 8 - bytes; 46 | while(--bytes) length |= *lengthData++ << shift, shift += 8; 47 | return length; 48 | }; 49 | 50 | auto offsetData = offsets.data(); 51 | auto offsetRead = [&]() -> uint { 52 | uint offset = 0; 53 | offset |= *offsetData++ << 0; if(index < 1 << 8) return offset; 54 | offset |= *offsetData++ << 8; if(index < 1 << 16) return offset; 55 | offset |= *offsetData++ << 16; if(index < 1 << 24) return offset; 56 | offset |= *offsetData++ << 24; return offset; 57 | }; 58 | 59 | while(index < size) { 60 | if(!flagRead()) { 61 | output[index++] = literalRead(); 62 | } else { 63 | uint length = lengthRead() + 6; 64 | uint offset = index - offsetRead(); 65 | while(length--) output[index++] = output[offset++]; 66 | } 67 | } 68 | 69 | return output; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /string/view.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline string_view::string_view() { 6 | _string = nullptr; 7 | _data = ""; 8 | _size = 0; 9 | } 10 | 11 | inline string_view::string_view(const string_view& source) { 12 | if(this == &source) return; 13 | _string = nullptr; 14 | _data = source._data; 15 | _size = source._size; 16 | } 17 | 18 | inline string_view::string_view(string_view&& source) { 19 | if(this == &source) return; 20 | _string = source._string; 21 | _data = source._data; 22 | _size = source._size; 23 | source._string = nullptr; 24 | } 25 | 26 | inline string_view::string_view(const char* data) { 27 | _string = nullptr; 28 | _data = data; 29 | _size = -1; //defer length calculation, as it is often unnecessary 30 | } 31 | 32 | inline string_view::string_view(const char* data, uint size) { 33 | _string = nullptr; 34 | _data = data; 35 | _size = size; 36 | } 37 | 38 | inline string_view::string_view(const string& source) { 39 | _string = nullptr; 40 | _data = source.data(); 41 | _size = source.size(); 42 | } 43 | 44 | template 45 | inline string_view::string_view(P&&... p) { 46 | _string = new string{forward

(p)...}; 47 | _data = _string->data(); 48 | _size = _string->size(); 49 | } 50 | 51 | inline string_view::~string_view() { 52 | if(_string) delete _string; 53 | } 54 | 55 | inline auto string_view::operator=(const string_view& source) -> type& { 56 | if(this == &source) return *this; 57 | _string = nullptr; 58 | _data = source._data; 59 | _size = source._size; 60 | return *this; 61 | } 62 | 63 | inline auto string_view::operator=(string_view&& source) -> type& { 64 | if(this == &source) return *this; 65 | _string = source._string; 66 | _data = source._data; 67 | _size = source._size; 68 | source._string = nullptr; 69 | return *this; 70 | } 71 | 72 | inline string_view::operator bool() const { 73 | return _size > 0; 74 | } 75 | 76 | inline string_view::operator const char*() const { 77 | return _data; 78 | } 79 | 80 | inline auto string_view::data() const -> const char* { 81 | return _data; 82 | } 83 | 84 | inline auto string_view::size() const -> uint { 85 | if(_size < 0) _size = strlen(_data); 86 | return _size; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /vector/iterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template 6 | struct vector_iterator { 7 | vector_iterator(vector& self, uint64_t offset) : self(self), offset(offset) {} 8 | auto operator*() -> T& { return self.operator[](offset); } 9 | auto operator->() -> T* { return self.operator[](offset); } 10 | auto operator!=(const vector_iterator& source) const -> bool { return offset != source.offset; } 11 | auto operator++() -> vector_iterator& { return offset++, *this; } 12 | 13 | private: 14 | vector& self; 15 | uint64_t offset; 16 | }; 17 | 18 | template 19 | struct vector_iterator_const { 20 | vector_iterator_const(const vector& self, uint64_t offset) : self(self), offset(offset) {} 21 | auto operator*() -> const T& { return self.operator[](offset); } 22 | auto operator->() -> T* { return self.operator[](offset); } 23 | auto operator!=(const vector_iterator_const& source) const -> bool { return offset != source.offset; } 24 | auto operator++() -> vector_iterator_const& { return offset++, *this; } 25 | 26 | private: 27 | const vector& self; 28 | uint64_t offset; 29 | }; 30 | 31 | template 32 | struct vector_reverse_iterator { 33 | vector_reverse_iterator(vector& self, uint64_t offset) : self(self), offset(offset) {} 34 | auto operator*() -> T& { return self.operator[](offset); } 35 | auto operator->() -> T* { return self.operator[](offset); } 36 | auto operator!=(const vector_reverse_iterator& source) const -> bool { return offset != source.offset; } 37 | auto operator++() -> vector_reverse_iterator& { return offset--, *this; } 38 | 39 | private: 40 | vector& self; 41 | uint64_t offset; 42 | }; 43 | 44 | template 45 | struct vector_reverse_iterator_const { 46 | vector_reverse_iterator_const(const vector& self, uint64_t offset) : self(self), offset(offset) {} 47 | auto operator*() -> const T& { return self.operator[](offset); } 48 | auto operator->() -> T* { return self.operator[](offset); } 49 | auto operator!=(const vector_reverse_iterator_const& source) const -> bool { return offset != source.offset; } 50 | auto operator++() -> vector_reverse_iterator_const& { return offset--, *this; } 51 | 52 | private: 53 | const vector& self; 54 | uint64_t offset; 55 | }; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /string/match.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | //todo: these functions are not binary-safe 6 | 7 | inline auto string::match(string_view source) const -> bool { 8 | const char* s = data(); 9 | const char* p = source.data(); 10 | 11 | const char* cp = nullptr; 12 | const char* mp = nullptr; 13 | while(*s && *p != '*') { 14 | if(*p != '?' && *s != *p) return false; 15 | p++, s++; 16 | } 17 | while(*s) { 18 | if(*p == '*') { 19 | if(!*++p) return true; 20 | mp = p, cp = s + 1; 21 | } else if(*p == '?' || *p == *s) { 22 | p++, s++; 23 | } else { 24 | p = mp, s = cp++; 25 | } 26 | } 27 | while(*p == '*') p++; 28 | return !*p; 29 | } 30 | 31 | inline auto string::imatch(string_view source) const -> bool { 32 | static auto chrlower = [](char c) -> char { 33 | return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; 34 | }; 35 | 36 | const char* s = data(); 37 | const char* p = source.data(); 38 | 39 | const char* cp = nullptr; 40 | const char* mp = nullptr; 41 | while(*s && *p != '*') { 42 | if(*p != '?' && chrlower(*s) != chrlower(*p)) return false; 43 | p++, s++; 44 | } 45 | while(*s) { 46 | if(*p == '*') { 47 | if(!*++p) return true; 48 | mp = p, cp = s + 1; 49 | } else if(*p == '?' || chrlower(*p) == chrlower(*s)) { 50 | p++, s++; 51 | } else { 52 | p = mp, s = cp++; 53 | } 54 | } 55 | while(*p == '*') p++; 56 | return !*p; 57 | } 58 | 59 | inline auto tokenize(const char* s, const char* p) -> bool { 60 | while(*s) { 61 | if(*p == '*') { 62 | while(*s) if(tokenize(s++, p + 1)) return true; 63 | return !*++p; 64 | } 65 | if(*s++ != *p++) return false; 66 | } 67 | while(*p == '*') p++; 68 | return !*p; 69 | } 70 | 71 | inline auto tokenize(vector& list, const char* s, const char* p) -> bool { 72 | while(*s) { 73 | if(*p == '*') { 74 | const char* b = s; 75 | while(*s) { 76 | if(tokenize(list, s++, p + 1)) { 77 | list.prepend(slice(b, 0, --s - b)); 78 | return true; 79 | } 80 | } 81 | list.prepend(b); 82 | return !*++p; 83 | } 84 | if(*s++ != *p++) return false; 85 | } 86 | while(*p == '*') { list.prepend(s); p++; } 87 | return !*p; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /stdint.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_MSC_VER) 4 | typedef signed char int8_t; 5 | typedef signed short int16_t; 6 | typedef signed int int32_t; 7 | typedef signed long long int64_t; 8 | typedef int64_t intmax_t; 9 | #if defined(_WIN64) 10 | typedef int64_t intptr_t; 11 | #else 12 | typedef int32_t intptr_t; 13 | #endif 14 | 15 | typedef unsigned char uint8_t; 16 | typedef unsigned short uint16_t; 17 | typedef unsigned int uint32_t; 18 | typedef unsigned long long uint64_t; 19 | typedef uint64_t uintmax_t; 20 | #if defined(_WIN64) 21 | typedef uint64_t uintptr_t; 22 | #else 23 | typedef uint32_t uintptr_t; 24 | #endif 25 | #else 26 | #include 27 | #endif 28 | 29 | //note: (u)intmax actually mean it: use as many bits as is possible 30 | #if defined(__SIZEOF_INT128__) 31 | using int128_t = signed __int128; 32 | using uint128_t = unsigned __int128; 33 | 34 | #define INTMAX_BITS 128 35 | using intmax = int128_t; 36 | using uintmax = uint128_t; 37 | #else 38 | #define INTMAX_BITS 64 39 | using intmax = intmax_t; 40 | using uintmax = uintmax_t; 41 | #endif 42 | 43 | using intptr = intptr_t; 44 | using uintptr = uintptr_t; 45 | 46 | using float32_t = float; 47 | using float64_t = double; 48 | //note: long double size is not reliable across platforms 49 | //using float80_t = long double; 50 | 51 | static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" ); 52 | static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size"); 53 | static_assert(sizeof(int32_t) == 4, "int32_t is not of the correct size"); 54 | static_assert(sizeof(int64_t) == 8, "int64_t is not of the correct size"); 55 | 56 | static_assert(sizeof(uint8_t) == 1, "int8_t is not of the correct size" ); 57 | static_assert(sizeof(uint16_t) == 2, "int16_t is not of the correct size"); 58 | static_assert(sizeof(uint32_t) == 4, "int32_t is not of the correct size"); 59 | static_assert(sizeof(uint64_t) == 8, "int64_t is not of the correct size"); 60 | 61 | static_assert(sizeof(float) >= 4, "float32_t is not of the correct size"); 62 | static_assert(sizeof(double) >= 8, "float64_t is not of the correct size"); 63 | //static_assert(sizeof(long double) >= 10, "float80_t is not of the correct size"); 64 | 65 | using uint = unsigned int; 66 | using real32_t = float; 67 | using real64_t = double; 68 | -------------------------------------------------------------------------------- /string/compare.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template 6 | inline auto string::_compare(const char* target, uint capacity, const char* source, uint size) -> int { 7 | if(Insensitive) return memory::icompare(target, capacity, source, size); 8 | return memory::compare(target, capacity, source, size); 9 | } 10 | 11 | //size() + 1 includes null-terminator; required to properly compare strings of differing lengths 12 | inline auto string::compare(string_view x, string_view y) -> int { 13 | return memory::compare(x.data(), x.size() + 1, y.data(), y.size() + 1); 14 | } 15 | 16 | inline auto string::icompare(string_view x, string_view y) -> int { 17 | return memory::icompare(x.data(), x.size() + 1, y.data(), y.size() + 1); 18 | } 19 | 20 | inline auto string::compare(string_view source) const -> int { 21 | return memory::compare(data(), size() + 1, source.data(), source.size() + 1); 22 | } 23 | 24 | inline auto string::icompare(string_view source) const -> int { 25 | return memory::icompare(data(), size() + 1, source.data(), source.size() + 1); 26 | } 27 | 28 | inline auto string::equals(string_view source) const -> bool { 29 | if(size() != source.size()) return false; 30 | return memory::compare(data(), source.data(), source.size()) == 0; 31 | } 32 | 33 | inline auto string::iequals(string_view source) const -> bool { 34 | if(size() != source.size()) return false; 35 | return memory::icompare(data(), source.data(), source.size()) == 0; 36 | } 37 | 38 | inline auto string::beginsWith(string_view source) const -> bool { 39 | if(source.size() > size()) return false; 40 | return memory::compare(data(), source.data(), source.size()) == 0; 41 | } 42 | 43 | inline auto string::ibeginsWith(string_view source) const -> bool { 44 | if(source.size() > size()) return false; 45 | return memory::icompare(data(), source.data(), source.size()) == 0; 46 | } 47 | 48 | inline auto string::endsWith(string_view source) const -> bool { 49 | if(source.size() > size()) return false; 50 | return memory::compare(data() + size() - source.size(), source.data(), source.size()) == 0; 51 | } 52 | 53 | inline auto string::iendsWith(string_view source) const -> bool { 54 | if(source.size() > size()) return false; 55 | return memory::icompare(data() + size() - source.size(), source.data(), source.size()) == 0; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /galois-field.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //table-driven galois field modulo 2 4 | //do not use with GF(2^17) or larger 5 | 6 | namespace nall { 7 | 8 | template 9 | struct GaloisField { 10 | using type = GaloisField; 11 | 12 | GaloisField(uint x = 0) : x(x) {} 13 | operator field() const { return x; } 14 | 15 | auto operator^(field y) const -> type { return x ^ y; } 16 | auto operator+(field y) const -> type { return x ^ y; } 17 | auto operator-(field y) const -> type { return x ^ y; } 18 | auto operator*(field y) const -> type { return x && y ? exp(log(x) + log(y)) : 0; } 19 | auto operator/(field y) const -> type { return x && y ? exp(log(x) + Elements - log(y)) : 0; } 20 | 21 | auto& operator =(field y) { return x = y, *this; } 22 | auto& operator^=(field y) { return x = operator^(y), *this; } 23 | auto& operator+=(field y) { return x = operator^(y), *this; } 24 | auto& operator-=(field y) { return x = operator^(y), *this; } 25 | auto& operator*=(field y) { return x = operator*(y), *this; } 26 | auto& operator/=(field y) { return x = operator/(y), *this; } 27 | 28 | auto pow(field y) const -> type { return exp(log(x) * y); } 29 | auto inv() const -> type { return exp(Elements - log(x)); } // 1/x 30 | 31 | static auto log(uint x) -> uint { 32 | enum : uint { Size = bit::round(Elements), Mask = Size - 1 }; 33 | static array log = [] { 34 | uint shift = 0, polynomial = Polynomial; 35 | while(polynomial >>= 1) shift++; 36 | shift--; 37 | 38 | array log; 39 | field x = 1; 40 | for(uint n : range(Elements)) { 41 | log[x] = n; 42 | x = x << 1 ^ (x >> shift ? Polynomial : 0); 43 | } 44 | log[0] = 0; //-inf (undefined) 45 | return log; 46 | }(); 47 | return log[x & Mask]; 48 | } 49 | 50 | static auto exp(uint x) -> uint { 51 | static array exp = [] { 52 | uint shift = 0, polynomial = Polynomial; 53 | while(polynomial >>= 1) shift++; 54 | shift--; 55 | 56 | array exp; 57 | field x = 1; 58 | for(uint n : range(Elements)) { 59 | exp[n] = x; 60 | x = x << 1 ^ (x >> shift ? Polynomial : 0); 61 | } 62 | return exp; 63 | }(); 64 | return exp[x % Elements]; 65 | } 66 | 67 | field x; 68 | }; 69 | 70 | } 71 | -------------------------------------------------------------------------------- /dsp/resampler/cubic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace nall::DSP::Resampler { 8 | 9 | struct Cubic { 10 | auto inputFrequency() const -> double { return _inputFrequency; } 11 | auto outputFrequency() const -> double { return _outputFrequency; } 12 | 13 | auto reset(double inputFrequency, double outputFrequency = 0, uint queueSize = 0) -> void; 14 | auto setInputFrequency(double inputFrequency) -> void; 15 | auto pending() const -> bool; 16 | auto read() -> double; 17 | auto write(double sample) -> void; 18 | auto serialize(serializer&) -> void; 19 | 20 | private: 21 | double _inputFrequency; 22 | double _outputFrequency; 23 | 24 | double _ratio; 25 | double _fraction; 26 | double _history[4]; 27 | queue _samples; 28 | }; 29 | 30 | inline auto Cubic::reset(double inputFrequency, double outputFrequency, uint queueSize) -> void { 31 | _inputFrequency = inputFrequency; 32 | _outputFrequency = outputFrequency ? outputFrequency : _inputFrequency; 33 | 34 | _ratio = _inputFrequency / _outputFrequency; 35 | _fraction = 0.0; 36 | for(auto& sample : _history) sample = 0.0; 37 | _samples.resize(queueSize ? queueSize : _outputFrequency * 0.02); //default to 20ms max queue size 38 | } 39 | 40 | inline auto Cubic::setInputFrequency(double inputFrequency) -> void { 41 | _inputFrequency = inputFrequency; 42 | _ratio = _inputFrequency / _outputFrequency; 43 | } 44 | 45 | inline auto Cubic::pending() const -> bool { 46 | return _samples.pending(); 47 | } 48 | 49 | inline auto Cubic::read() -> double { 50 | return _samples.read(); 51 | } 52 | 53 | inline auto Cubic::write(double sample) -> void { 54 | auto& mu = _fraction; 55 | auto& s = _history; 56 | 57 | s[0] = s[1]; 58 | s[1] = s[2]; 59 | s[2] = s[3]; 60 | s[3] = sample; 61 | 62 | while(mu <= 1.0) { 63 | double A = s[3] - s[2] - s[0] + s[1]; 64 | double B = s[0] - s[1] - A; 65 | double C = s[2] - s[0]; 66 | double D = s[1]; 67 | 68 | _samples.write(A * mu * mu * mu + B * mu * mu + C * mu + D); 69 | mu += _ratio; 70 | } 71 | 72 | mu -= 1.0; 73 | } 74 | 75 | inline auto Cubic::serialize(serializer& s) -> void { 76 | s.real(_inputFrequency); 77 | s.real(_outputFrequency); 78 | s.real(_ratio); 79 | s.real(_fraction); 80 | s.array(_history); 81 | _samples.serialize(s); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /decode/bmp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Decode { 4 | 5 | struct BMP { 6 | BMP() = default; 7 | BMP(const string& filename) { load(filename); } 8 | BMP(const uint8_t* data, uint size) { load(data, size); } 9 | 10 | explicit operator bool() const { return _data; } 11 | 12 | auto reset() -> void { 13 | if(_data) { delete[] _data; _data = nullptr; } 14 | } 15 | 16 | auto data() -> uint32_t* { return _data; } 17 | auto data() const -> const uint32_t* { return _data; } 18 | auto width() const -> uint { return _width; } 19 | auto height() const -> uint { return _height; } 20 | 21 | auto load(const string& filename) -> bool { 22 | auto buffer = file::read(filename); 23 | return load(buffer.data(), buffer.size()); 24 | } 25 | 26 | auto load(const uint8_t* data, uint size) -> bool { 27 | if(size < 0x36) return false; 28 | const uint8_t* p = data; 29 | if(read(p, 2) != 0x4d42) return false; //signature 30 | read(p, 8); 31 | uint offset = read(p, 4); 32 | if(read(p, 4) != 40) return false; //DIB size 33 | int width = read(p, 4); 34 | if(width < 0) return false; 35 | int height = read(p, 4); 36 | bool flip = height < 0; 37 | if(flip) height = -height; 38 | read(p, 2); 39 | uint bitsPerPixel = read(p, 2); 40 | if(bitsPerPixel != 24 && bitsPerPixel != 32) return false; 41 | if(read(p, 4) != 0) return false; //compression type 42 | 43 | _width = width; 44 | _height = height; 45 | _data = new uint32_t[width * height]; 46 | 47 | uint bytesPerPixel = bitsPerPixel / 8; 48 | uint alignedWidth = width * bytesPerPixel; 49 | uint paddingLength = 0; 50 | while(alignedWidth % 4) alignedWidth++, paddingLength++; 51 | 52 | p = data + offset; 53 | for(auto y : range(height)) { 54 | uint32_t* output = flip ? _data + (height - 1 - y) * width : _data + y * width; 55 | for(auto x : range(width)) { 56 | *output++ = read(p, bytesPerPixel) | (bitsPerPixel == 24 ? 255u << 24 : 0); 57 | } 58 | if(paddingLength) read(p, paddingLength); 59 | } 60 | 61 | return true; 62 | } 63 | 64 | private: 65 | uint32_t* _data = nullptr; 66 | uint _width = 0; 67 | uint _height = 0; 68 | 69 | auto read(const uint8_t*& buffer, uint length) -> uintmax { 70 | uintmax result = 0; 71 | for(auto n : range(length)) result |= (uintmax)*buffer++ << (n << 3); 72 | return result; 73 | } 74 | }; 75 | 76 | } 77 | -------------------------------------------------------------------------------- /map.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall { 6 | 7 | template struct map { 8 | struct node_t { 9 | T key; 10 | U value; 11 | node_t() = default; 12 | node_t(const T& key) : key(key) {} 13 | node_t(const T& key, const U& value) : key(key), value(value) {} 14 | auto operator< (const node_t& source) const -> bool { return key < source.key; } 15 | auto operator==(const node_t& source) const -> bool { return key == source.key; } 16 | }; 17 | 18 | auto find(const T& key) const -> maybe { 19 | if(auto node = root.find({key})) return node().value; 20 | return nothing; 21 | } 22 | 23 | auto insert(const T& key, const U& value) -> void { root.insert({key, value}); } 24 | auto remove(const T& key) -> void { root.remove({key}); } 25 | auto size() const -> unsigned { return root.size(); } 26 | auto reset() -> void { root.reset(); } 27 | 28 | auto begin() -> typename set::iterator { return root.begin(); } 29 | auto end() -> typename set::iterator { return root.end(); } 30 | 31 | auto begin() const -> const typename set::iterator { return root.begin(); } 32 | auto end() const -> const typename set::iterator { return root.end(); } 33 | 34 | protected: 35 | set root; 36 | }; 37 | 38 | template struct bimap { 39 | auto find(const T& key) const -> maybe { return tmap.find(key); } 40 | auto find(const U& key) const -> maybe { return umap.find(key); } 41 | auto insert(const T& key, const U& value) -> void { tmap.insert(key, value); umap.insert(value, key); } 42 | auto remove(const T& key) -> void { if(auto p = tmap.find(key)) { umap.remove(p().value); tmap.remove(key); } } 43 | auto remove(const U& key) -> void { if(auto p = umap.find(key)) { tmap.remove(p().value); umap.remove(key); } } 44 | auto size() const -> unsigned { return tmap.size(); } 45 | auto reset() -> void { tmap.reset(); umap.reset(); } 46 | 47 | auto begin() -> typename set::node_t>::iterator { return tmap.begin(); } 48 | auto end() -> typename set::node_t>::iterator { return tmap.end(); } 49 | 50 | auto begin() const -> const typename set::node_t>::iterator { return tmap.begin(); } 51 | auto end() const -> const typename set::node_t>::iterator { return tmap.end(); } 52 | 53 | protected: 54 | map tmap; 55 | map umap; 56 | }; 57 | 58 | } 59 | -------------------------------------------------------------------------------- /array.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace nall { 9 | 10 | template struct array; 11 | 12 | //usage: int x[256] => array x 13 | template struct array { 14 | array() = default; 15 | 16 | array(const initializer_list& source) { 17 | uint index = 0; 18 | for(auto& value : source) { 19 | operator[](index++) = value; 20 | } 21 | } 22 | 23 | operator array_span() { 24 | return {data(), size()}; 25 | } 26 | 27 | operator array_view() const { 28 | return {data(), size()}; 29 | } 30 | 31 | alwaysinline auto operator[](uint index) -> T& { 32 | #ifdef DEBUG 33 | struct out_of_bounds {}; 34 | if(index >= Size) throw out_of_bounds{}; 35 | #endif 36 | return values[index]; 37 | } 38 | 39 | alwaysinline auto operator[](uint index) const -> const T& { 40 | #ifdef DEBUG 41 | struct out_of_bounds {}; 42 | if(index >= Size) throw out_of_bounds{}; 43 | #endif 44 | return values[index]; 45 | } 46 | 47 | alwaysinline auto operator()(uint index, const T& fallback = {}) const -> const T& { 48 | if(index >= Size) return fallback; 49 | return values[index]; 50 | } 51 | 52 | auto fill(const T& fill = {}) -> array& { 53 | for(auto& value : values) value = fill; 54 | return *this; 55 | } 56 | 57 | auto data() -> T* { return values; } 58 | auto data() const -> const T* { return values; } 59 | auto size() const -> uint { return Size; } 60 | 61 | auto begin() -> T* { return &values[0]; } 62 | auto end() -> T* { return &values[Size]; } 63 | 64 | auto begin() const -> const T* { return &values[0]; } 65 | auto end() const -> const T* { return &values[Size]; } 66 | 67 | private: 68 | T values[Size]; 69 | }; 70 | 71 | template inline auto from_array(uint index) -> T { 72 | static const array table{p...}; 73 | struct out_of_bounds {}; 74 | #if defined(DEBUG) 75 | if(index >= sizeof...(p)) throw out_of_bounds{}; 76 | #endif 77 | return table[index]; 78 | } 79 | 80 | template inline auto from_array(uint index) -> int64_t { 81 | static const array table{p...}; 82 | struct out_of_bounds {}; 83 | #if defined(DEBUG) 84 | if(index >= sizeof...(p)) throw out_of_bounds{}; 85 | #endif 86 | return table[index]; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /string/pascal.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | struct string_pascal { 6 | using type = string_pascal; 7 | 8 | string_pascal(const char* text = nullptr) { 9 | if(text && *text) { 10 | uint size = strlen(text); 11 | _data = memory::allocate(sizeof(uint) + size + 1); 12 | ((uint*)_data)[0] = size; 13 | memory::copy(_data + sizeof(uint), text, size); 14 | _data[sizeof(uint) + size] = 0; 15 | } 16 | } 17 | 18 | string_pascal(const string& text) { 19 | if(text.size()) { 20 | _data = memory::allocate(sizeof(uint) + text.size() + 1); 21 | ((uint*)_data)[0] = text.size(); 22 | memory::copy(_data + sizeof(uint), text.data(), text.size()); 23 | _data[sizeof(uint) + text.size()] = 0; 24 | } 25 | } 26 | 27 | string_pascal(const string_pascal& source) { operator=(source); } 28 | string_pascal(string_pascal&& source) { operator=(move(source)); } 29 | 30 | ~string_pascal() { 31 | if(_data) memory::free(_data); 32 | } 33 | 34 | explicit operator bool() const { return _data; } 35 | operator const char*() const { return _data ? _data + sizeof(uint) : nullptr; } 36 | operator string() const { return _data ? string{_data + sizeof(uint)} : ""; } 37 | 38 | auto operator=(const string_pascal& source) -> type& { 39 | if(this == &source) return *this; 40 | if(_data) { memory::free(_data); _data = nullptr; } 41 | if(source._data) { 42 | uint size = source.size(); 43 | _data = memory::allocate(sizeof(uint) + size); 44 | memory::copy(_data, source._data, sizeof(uint) + size); 45 | } 46 | return *this; 47 | } 48 | 49 | auto operator=(string_pascal&& source) -> type& { 50 | if(this == &source) return *this; 51 | if(_data) memory::free(_data); 52 | _data = source._data; 53 | source._data = nullptr; 54 | return *this; 55 | } 56 | 57 | auto operator==(string_view source) const -> bool { 58 | return size() == source.size() && memory::compare(data(), source.data(), size()) == 0; 59 | } 60 | 61 | auto operator!=(string_view source) const -> bool { 62 | return size() != source.size() || memory::compare(data(), source.data(), size()) != 0; 63 | } 64 | 65 | auto data() const -> char* { 66 | if(!_data) return nullptr; 67 | return _data + sizeof(uint); 68 | } 69 | 70 | auto size() const -> uint { 71 | if(!_data) return 0; 72 | return ((uint*)_data)[0]; 73 | } 74 | 75 | protected: 76 | char* _data = nullptr; 77 | }; 78 | 79 | } 80 | -------------------------------------------------------------------------------- /arithmetic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //multi-precision arithmetic 4 | //warning: each size is quadratically more expensive than the size before it! 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | namespace nall { 14 | template struct ArithmeticNatural; 15 | template<> struct ArithmeticNatural< 8> { using type = uint8_t; }; 16 | template<> struct ArithmeticNatural< 16> { using type = uint16_t; }; 17 | template<> struct ArithmeticNatural< 32> { using type = uint32_t; }; 18 | template<> struct ArithmeticNatural< 64> { using type = uint64_t; }; 19 | #if INTMAX_BITS >= 128 20 | template<> struct ArithmeticNatural<128> { using type = uint128_t; }; 21 | #endif 22 | } 23 | 24 | #if INTMAX_BITS < 128 25 | #define PairBits 128 26 | #define TypeBits 64 27 | #define HalfBits 32 28 | #include 29 | #undef PairBits 30 | #undef TypeBits 31 | #undef HalfBits 32 | #endif 33 | 34 | #define PairBits 256 35 | #define TypeBits 128 36 | #define HalfBits 64 37 | #include 38 | #undef PairBits 39 | #undef TypeBits 40 | #undef HalfBits 41 | 42 | #define PairBits 512 43 | #define TypeBits 256 44 | #define HalfBits 128 45 | #include 46 | #undef PairBits 47 | #undef TypeBits 48 | #undef HalfBits 49 | 50 | #define PairBits 1024 51 | #define TypeBits 512 52 | #define HalfBits 256 53 | #include 54 | #undef PairBits 55 | #undef TypeBits 56 | #undef HalfBits 57 | 58 | #define PairBits 2048 59 | #define TypeBits 1024 60 | #define HalfBits 512 61 | #include 62 | #undef PairBits 63 | #undef TypeBits 64 | #undef HalfBits 65 | 66 | #define PairBits 4096 67 | #define TypeBits 2048 68 | #define HalfBits 1024 69 | #include 70 | #undef PairBits 71 | #undef TypeBits 72 | #undef HalfBits 73 | 74 | #define PairBits 8192 75 | #define TypeBits 4096 76 | #define HalfBits 2048 77 | #include 78 | #undef PairBits 79 | #undef TypeBits 80 | #undef HalfBits 81 | 82 | namespace nall { 83 | //TODO: these types are for expressing smaller bit ranges in class interfaces 84 | //for instance, XChaCha20 taking a 192-bit nonce 85 | //however, they still allow more bits than expressed ... 86 | //some sort of wrapper needs to be devised to ensure these sizes are masked and wrap appropriately 87 | 88 | using uint192_t = uint256_t; 89 | } 90 | -------------------------------------------------------------------------------- /string/allocator/copy-on-write.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline string::string() : _data(nullptr), _refs(nullptr), _capacity(0), _size(0) { 6 | } 7 | 8 | template 9 | inline auto string::get() -> T* { 10 | static char _null[] = ""; 11 | if(!_data) return (T*)_null; 12 | if(*_refs > 1) _data = _copy(); //make unique for write operations 13 | return (T*)_data; 14 | } 15 | 16 | template 17 | inline auto string::data() const -> const T* { 18 | static const char _null[] = ""; 19 | if(!_data) return (const T*)_null; 20 | return (const T*)_data; 21 | } 22 | 23 | inline auto string::reset() -> type& { 24 | if(_data && !--*_refs) { 25 | memory::free(_data); 26 | _data = nullptr; //_refs = nullptr; is unnecessary 27 | } 28 | _capacity = 0; 29 | _size = 0; 30 | return *this; 31 | } 32 | 33 | inline auto string::reserve(uint capacity) -> type& { 34 | if(capacity > _capacity) { 35 | _capacity = bit::round(max(31u, capacity) + 1) - 1; 36 | _data = _data ? _copy() : _allocate(); 37 | } 38 | return *this; 39 | } 40 | 41 | inline auto string::resize(uint size) -> type& { 42 | reserve(size); 43 | get()[_size = size] = 0; 44 | return *this; 45 | } 46 | 47 | inline auto string::operator=(const string& source) -> string& { 48 | if(&source == this) return *this; 49 | reset(); 50 | if(source._data) { 51 | _data = source._data; 52 | _refs = source._refs; 53 | _capacity = source._capacity; 54 | _size = source._size; 55 | ++*_refs; 56 | } 57 | return *this; 58 | } 59 | 60 | inline auto string::operator=(string&& source) -> string& { 61 | if(&source == this) return *this; 62 | reset(); 63 | _data = source._data; 64 | _refs = source._refs; 65 | _capacity = source._capacity; 66 | _size = source._size; 67 | source._data = nullptr; 68 | source._refs = nullptr; 69 | source._capacity = 0; 70 | source._size = 0; 71 | return *this; 72 | } 73 | 74 | inline auto string::_allocate() -> char* { 75 | auto _temp = memory::allocate(_capacity + 1 + sizeof(uint)); 76 | *_temp = 0; 77 | _refs = (uint*)(_temp + _capacity + 1); //this will always be aligned by 32 via reserve() 78 | *_refs = 1; 79 | return _temp; 80 | } 81 | 82 | inline auto string::_copy() -> char* { 83 | auto _temp = memory::allocate(_capacity + 1 + sizeof(uint)); 84 | memory::copy(_temp, _data, _size = min(_capacity, _size)); 85 | _temp[_size] = 0; 86 | --*_refs; 87 | _refs = (uint*)(_temp + _capacity + 1); 88 | *_refs = 1; 89 | return _temp; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /decode/wav.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace nall::Decode { 7 | 8 | struct WAV { 9 | auto open(const string& filename) -> bool; 10 | auto close() -> void; 11 | auto read() -> uint64_t; 12 | auto end() const -> bool; 13 | auto size() const -> uint64_t; 14 | 15 | file_buffer fp; 16 | uint channels = 0; 17 | uint frequency = 0; 18 | uint bitrate = 0; 19 | uint samples = 0; 20 | uint headerSize = 0; 21 | }; 22 | 23 | inline auto WAV::open(const string& filename) -> bool { 24 | close(); 25 | 26 | if(fp = file::open(filename, file::mode::read)) { 27 | if(fp.read() != 'R') return false; 28 | if(fp.read() != 'I') return false; 29 | if(fp.read() != 'F') return false; 30 | if(fp.read() != 'F') return false; 31 | 32 | uint32_t chunkSize = fp.readl(4); 33 | 34 | if(fp.read() != 'W') return false; 35 | if(fp.read() != 'A') return false; 36 | if(fp.read() != 'V') return false; 37 | if(fp.read() != 'E') return false; 38 | 39 | if(fp.read() != 'f') return false; 40 | if(fp.read() != 'm') return false; 41 | if(fp.read() != 't') return false; 42 | if(fp.read() != ' ') return false; 43 | 44 | uint32_t subchunkSize = fp.readl(4); 45 | if(subchunkSize != 16) return false; 46 | 47 | uint16_t format = fp.readl(2); 48 | if(format != 1) return false; //only PCM is supported 49 | 50 | channels = fp.readl(2); 51 | frequency = fp.readl(4); 52 | uint32_t byteRate = fp.readl(4); 53 | uint16_t blockAlign = fp.readl(2); 54 | bitrate = fp.readl(2); 55 | 56 | //todo: handle LIST chunk better than this 57 | while(!fp.end() && fp.read() != 'd'); 58 | while(!fp.end() && fp.read() != 'a'); 59 | while(!fp.end() && fp.read() != 't'); 60 | while(!fp.end() && fp.read() != 'a'); 61 | if(fp.end()) return false; 62 | 63 | uint32_t dataSize = fp.readl(4); 64 | uint32_t remaining = fp.size() - fp.offset(); 65 | samples = remaining / (bitrate / 8) / channels; 66 | headerSize = fp.offset(); 67 | return true; 68 | } 69 | 70 | return false; 71 | } 72 | 73 | inline auto WAV::close() -> void { 74 | fp.close(); 75 | channels = 0; 76 | frequency = 0; 77 | bitrate = 0; 78 | samples = 0; 79 | } 80 | 81 | inline auto WAV::read() -> uint64_t { 82 | return fp.readl((bitrate / 8) * channels); 83 | } 84 | 85 | inline auto WAV::end() const -> bool { 86 | return fp.end(); 87 | } 88 | 89 | inline auto WAV::size() const -> uint64_t { 90 | return samples * (bitrate / 8) * channels; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /windows/utf8.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | using uint = unsigned; 4 | 5 | namespace nall { 6 | //UTF-8 to UTF-16 7 | struct utf16_t { 8 | utf16_t(const char* s = "") { operator=(s); } 9 | ~utf16_t() { reset(); } 10 | 11 | utf16_t(const utf16_t&) = delete; 12 | auto operator=(const utf16_t&) -> utf16_t& = delete; 13 | 14 | auto operator=(const char* s) -> utf16_t& { 15 | reset(); 16 | if(!s) s = ""; 17 | length = MultiByteToWideChar(CP_UTF8, 0, s, -1, nullptr, 0); 18 | buffer = new wchar_t[length + 1]; 19 | MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length); 20 | buffer[length] = 0; 21 | return *this; 22 | } 23 | 24 | operator wchar_t*() { return buffer; } 25 | operator const wchar_t*() const { return buffer; } 26 | 27 | auto reset() -> void { 28 | delete[] buffer; 29 | length = 0; 30 | } 31 | 32 | auto data() -> wchar_t* { return buffer; } 33 | auto data() const -> const wchar_t* { return buffer; } 34 | 35 | auto size() const -> uint { return length; } 36 | 37 | private: 38 | wchar_t* buffer = nullptr; 39 | uint length = 0; 40 | }; 41 | 42 | //UTF-16 to UTF-8 43 | struct utf8_t { 44 | utf8_t(const wchar_t* s = L"") { operator=(s); } 45 | ~utf8_t() { reset(); } 46 | 47 | utf8_t(const utf8_t&) = delete; 48 | auto operator=(const utf8_t&) -> utf8_t& = delete; 49 | 50 | auto operator=(const wchar_t* s) -> utf8_t& { 51 | reset(); 52 | if(!s) s = L""; 53 | length = WideCharToMultiByte(CP_UTF8, 0, s, -1, nullptr, 0, nullptr, nullptr); 54 | buffer = new char[length + 1]; 55 | WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, nullptr, nullptr); 56 | buffer[length] = 0; 57 | return *this; 58 | } 59 | 60 | auto reset() -> void { 61 | delete[] buffer; 62 | length = 0; 63 | } 64 | 65 | operator char*() { return buffer; } 66 | operator const char*() const { return buffer; } 67 | 68 | auto data() -> char* { return buffer; } 69 | auto data() const -> const char* { return buffer; } 70 | 71 | auto size() const -> uint { return length; } 72 | 73 | private: 74 | char* buffer = nullptr; 75 | uint length = 0; 76 | }; 77 | 78 | inline auto utf8_arguments(int& argc, char**& argv) -> void { 79 | wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); 80 | argv = new char*[argc + 1](); 81 | for(uint i = 0; i < argc; i++) { 82 | argv[i] = new char[PATH_MAX]; 83 | strcpy(argv[i], nall::utf8_t(wargv[i])); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /bump-allocator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | struct bump_allocator { 6 | static constexpr uint32_t executable = 1 << 0; 7 | static constexpr uint32_t zero_fill = 1 << 1; 8 | 9 | ~bump_allocator() { 10 | reset(); 11 | } 12 | 13 | explicit operator bool() const { 14 | return _memory; 15 | } 16 | 17 | auto reset() -> void { 18 | free(_memory); 19 | _memory = nullptr; 20 | } 21 | 22 | auto resize(uint32_t capacity, uint32_t flags = 0) -> bool { 23 | reset(); 24 | _offset = 0; 25 | _capacity = capacity + 4095 & ~4095; //alignment 26 | _memory = (uint8_t*)malloc(_capacity); 27 | if(!_memory) return false; 28 | 29 | if(flags & executable) { 30 | #if defined(PLATFORM_WINDOWS) 31 | DWORD privileges; 32 | VirtualProtect((void*)_memory, _capacity, PAGE_EXECUTE_READWRITE, &privileges); 33 | #else 34 | mprotect(_memory, _capacity, PROT_READ | PROT_WRITE | PROT_EXEC); 35 | #endif 36 | } 37 | 38 | if(flags & zero_fill) { 39 | memset(_memory, 0x00, _capacity); 40 | } 41 | 42 | return true; 43 | } 44 | 45 | //release all acquired memory 46 | auto release(uint32_t flags = 0) -> void { 47 | _offset = 0; 48 | if(flags & zero_fill) memset(_memory, 0x00, _capacity); 49 | } 50 | 51 | auto capacity() const -> uint32_t { 52 | return _capacity; 53 | } 54 | 55 | auto available() const -> uint32_t { 56 | return _capacity - _offset; 57 | } 58 | 59 | //for allocating blocks of known size 60 | auto acquire(uint32_t size) -> uint8_t* { 61 | #ifdef DEBUG 62 | struct out_of_memory {}; 63 | if((_offset + size + 15 & ~15) > _capacity) throw out_of_memory{}; 64 | #endif 65 | auto memory = _memory + _offset; 66 | _offset = _offset + size + 15 & ~15; //alignment 67 | return memory; 68 | } 69 | 70 | //for allocating blocks of unknown size (eg for a dynamic recompiler code block) 71 | auto acquire() -> uint8_t* { 72 | #ifdef DEBUG 73 | struct out_of_memory {}; 74 | if(_offset > _capacity) throw out_of_memory{}; 75 | #endif 76 | return _memory + _offset; 77 | } 78 | 79 | //size can be reserved once the block size is known 80 | auto reserve(uint32_t size) -> void { 81 | #ifdef DEBUG 82 | struct out_of_memory {}; 83 | if((_offset + size + 15 & ~15) > _capacity) throw out_of_memory{}; 84 | #endif 85 | _offset = _offset + size + 15 & ~15; //alignment 86 | } 87 | 88 | private: 89 | uint8_t* _memory = nullptr; 90 | uint32_t _capacity = 0; 91 | uint32_t _offset = 0; 92 | }; 93 | 94 | } 95 | -------------------------------------------------------------------------------- /atoi.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall { 6 | 7 | constexpr inline auto toBinary_(const char* s, uintmax sum = 0) -> uintmax { 8 | return ( 9 | *s == '0' || *s == '1' ? toBinary_(s + 1, (sum << 1) | *s - '0') : 10 | *s == '\'' ? toBinary_(s + 1, sum) : 11 | sum 12 | ); 13 | } 14 | 15 | constexpr inline auto toOctal_(const char* s, uintmax sum = 0) -> uintmax { 16 | return ( 17 | *s >= '0' && *s <= '7' ? toOctal_(s + 1, (sum << 3) | *s - '0') : 18 | *s == '\'' ? toOctal_(s + 1, sum) : 19 | sum 20 | ); 21 | } 22 | 23 | constexpr inline auto toDecimal_(const char* s, uintmax sum = 0) -> uintmax { 24 | return ( 25 | *s >= '0' && *s <= '9' ? toDecimal_(s + 1, (sum * 10) + *s - '0') : 26 | *s == '\'' ? toDecimal_(s + 1, sum) : 27 | sum 28 | ); 29 | } 30 | 31 | constexpr inline auto toHex_(const char* s, uintmax sum = 0) -> uintmax { 32 | return ( 33 | *s >= 'A' && *s <= 'F' ? toHex_(s + 1, (sum << 4) | *s - 'A' + 10) : 34 | *s >= 'a' && *s <= 'f' ? toHex_(s + 1, (sum << 4) | *s - 'a' + 10) : 35 | *s >= '0' && *s <= '9' ? toHex_(s + 1, (sum << 4) | *s - '0') : 36 | *s == '\'' ? toHex_(s + 1, sum) : 37 | sum 38 | ); 39 | } 40 | 41 | // 42 | 43 | constexpr inline auto toBinary(const char* s) -> uintmax { 44 | return ( 45 | *s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? toBinary_(s + 2) : 46 | *s == '%' ? toBinary_(s + 1) : toBinary_(s) 47 | ); 48 | } 49 | 50 | constexpr inline auto toOctal(const char* s) -> uintmax { 51 | return ( 52 | *s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? toOctal_(s + 2) : 53 | toOctal_(s) 54 | ); 55 | } 56 | 57 | constexpr inline auto toHex(const char* s) -> uintmax { 58 | return ( 59 | *s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? toHex_(s + 2) : 60 | *s == '$' ? toHex_(s + 1) : toHex_(s) 61 | ); 62 | } 63 | 64 | // 65 | 66 | constexpr inline auto toNatural(const char* s) -> uintmax { 67 | return ( 68 | *s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? toBinary_(s + 2) : 69 | *s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? toOctal_(s + 2) : 70 | *s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? toHex_(s + 2) : 71 | *s == '%' ? toBinary_(s + 1) : *s == '$' ? toHex_(s + 1) : toDecimal_(s) 72 | ); 73 | } 74 | 75 | constexpr inline auto toInteger(const char* s) -> intmax { 76 | return ( 77 | *s == '+' ? +toNatural(s + 1) : *s == '-' ? -toNatural(s + 1) : toNatural(s) 78 | ); 79 | } 80 | 81 | // 82 | 83 | inline auto toReal(const char* s) -> double { 84 | return atof(s); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /image/interpolation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline auto image::isplit(uint64_t* c, uint64_t color) -> void { 6 | c[0] = (color & _alpha.mask()) >> _alpha.shift(); 7 | c[1] = (color & _red.mask() ) >> _red.shift(); 8 | c[2] = (color & _green.mask()) >> _green.shift(); 9 | c[3] = (color & _blue.mask() ) >> _blue.shift(); 10 | } 11 | 12 | inline auto image::imerge(const uint64_t* c) -> uint64_t { 13 | return c[0] << _alpha.shift() | c[1] << _red.shift() | c[2] << _green.shift() | c[3] << _blue.shift(); 14 | } 15 | 16 | inline auto image::interpolate1f(uint64_t a, uint64_t b, double x) -> uint64_t { 17 | return a * (1.0 - x) + b * x; 18 | } 19 | 20 | inline auto image::interpolate1f(uint64_t a, uint64_t b, uint64_t c, uint64_t d, double x, double y) -> uint64_t { 21 | return a * (1.0 - x) * (1.0 - y) + b * x * (1.0 - y) + c * (1.0 - x) * y + d * x * y; 22 | } 23 | 24 | inline auto image::interpolate1i(int64_t a, int64_t b, uint32_t x) -> uint64_t { 25 | return a + (((b - a) * x) >> 32); //a + (b - a) * x 26 | } 27 | 28 | inline auto image::interpolate1i(int64_t a, int64_t b, int64_t c, int64_t d, uint32_t x, uint32_t y) -> uint64_t { 29 | a = a + (((b - a) * x) >> 32); //a + (b - a) * x 30 | c = c + (((d - c) * x) >> 32); //c + (d - c) * x 31 | return a + (((c - a) * y) >> 32); //a + (c - a) * y 32 | } 33 | 34 | inline auto image::interpolate4f(uint64_t a, uint64_t b, double x) -> uint64_t { 35 | uint64_t o[4], pa[4], pb[4]; 36 | isplit(pa, a), isplit(pb, b); 37 | for(uint n = 0; n < 4; n++) o[n] = interpolate1f(pa[n], pb[n], x); 38 | return imerge(o); 39 | } 40 | 41 | inline auto image::interpolate4f(uint64_t a, uint64_t b, uint64_t c, uint64_t d, double x, double y) -> uint64_t { 42 | uint64_t o[4], pa[4], pb[4], pc[4], pd[4]; 43 | isplit(pa, a), isplit(pb, b), isplit(pc, c), isplit(pd, d); 44 | for(uint n = 0; n < 4; n++) o[n] = interpolate1f(pa[n], pb[n], pc[n], pd[n], x, y); 45 | return imerge(o); 46 | } 47 | 48 | inline auto image::interpolate4i(uint64_t a, uint64_t b, uint32_t x) -> uint64_t { 49 | uint64_t o[4], pa[4], pb[4]; 50 | isplit(pa, a), isplit(pb, b); 51 | for(uint n = 0; n < 4; n++) o[n] = interpolate1i(pa[n], pb[n], x); 52 | return imerge(o); 53 | } 54 | 55 | inline auto image::interpolate4i(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint32_t x, uint32_t y) -> uint64_t { 56 | uint64_t o[4], pa[4], pb[4], pc[4], pd[4]; 57 | isplit(pa, a), isplit(pb, b), isplit(pc, c), isplit(pd, d); 58 | for(uint n = 0; n < 4; n++) o[n] = interpolate1i(pa[n], pb[n], pc[n], pd[n], x, y); 59 | return imerge(o); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /locale.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | struct Locale { 6 | struct Dictionary { 7 | string location; 8 | string language; 9 | Markup::Node document; 10 | }; 11 | 12 | auto scan(string pathname) -> void { 13 | dictionaries.reset(); 14 | selected.reset(); 15 | for(auto filename : directory::icontents(pathname, "*.bml")) { 16 | Dictionary dictionary; 17 | dictionary.location = {pathname, filename}; 18 | dictionary.document = BML::unserialize(string::read(dictionary.location)); 19 | dictionary.language = dictionary.document["locale/language"].text(); 20 | dictionaries.append(dictionary); 21 | } 22 | } 23 | 24 | auto available() const -> vector { 25 | vector result; 26 | for(auto& dictionary : dictionaries) { 27 | result.append(dictionary.language); 28 | } 29 | return result; 30 | } 31 | 32 | auto select(string option) -> bool { 33 | selected.reset(); 34 | for(auto& dictionary : dictionaries) { 35 | if(option == Location::prefix(dictionary.location) || option == dictionary.language) { 36 | selected = dictionary; 37 | return true; 38 | } 39 | } 40 | return false; 41 | } 42 | 43 | template 44 | auto operator()(string ns, string input, P&&... p) const -> string { 45 | vector arguments{forward

(p)...}; 46 | if(selected) { 47 | for(auto node : selected().document) { 48 | if(node.name() == "namespace" && node.text() == ns) { 49 | for(auto map : node) { 50 | if(map.name() == "map" && map["input"].text() == input) { 51 | input = map["value"].text(); 52 | break; 53 | } 54 | } 55 | } 56 | } 57 | } 58 | for(uint index : range(arguments.size())) { 59 | input.replace({"{", index, "}"}, arguments[index]); 60 | } 61 | return input; 62 | } 63 | 64 | struct Namespace { 65 | Namespace(Locale& _locale, string _namespace) : _locale(_locale), _namespace(_namespace) {} 66 | 67 | template 68 | auto operator()(string input, P&&... p) const -> string { 69 | return _locale(_namespace, input, forward

(p)...); 70 | } 71 | 72 | template 73 | auto tr(string input, P&&... p) const -> string { 74 | return _locale(_namespace, input, forward

(p)...); 75 | } 76 | 77 | private: 78 | Locale& _locale; 79 | string _namespace; 80 | }; 81 | 82 | private: 83 | vector dictionaries; 84 | maybe selected; 85 | }; 86 | 87 | } 88 | -------------------------------------------------------------------------------- /string/allocator/small-string-optimization.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | small string optimization (SSO) allocator 5 | sizeof(string) == 8 + string::SSO 6 | 7 | utilizes a union to store small strings directly into text pointer 8 | bypasses the need to allocate heap memory for small strings 9 | requires extra computations, which can be slower for large strings 10 | 11 | pros: 12 | * potential for in-place resize 13 | * no heap allocation when (capacity < SSO) 14 | 15 | cons: 16 | * added overhead to fetch data() 17 | * pass-by-value requires heap allocation when (capacity >= SSO) 18 | 19 | */ 20 | 21 | namespace nall { 22 | 23 | inline string::string() { 24 | _data = nullptr; 25 | _capacity = SSO - 1; 26 | _size = 0; 27 | } 28 | 29 | template 30 | inline auto string::get() -> T* { 31 | if(_capacity < SSO) return (T*)_text; 32 | return (T*)_data; 33 | } 34 | 35 | template 36 | inline auto string::data() const -> const T* { 37 | if(_capacity < SSO) return (const T*)_text; 38 | return (const T*)_data; 39 | } 40 | 41 | inline auto string::reset() -> type& { 42 | if(_capacity >= SSO) memory::free(_data); 43 | _data = nullptr; 44 | _capacity = SSO - 1; 45 | _size = 0; 46 | return *this; 47 | } 48 | 49 | inline auto string::reserve(uint capacity) -> type& { 50 | if(capacity <= _capacity) return *this; 51 | capacity = bit::round(capacity + 1) - 1; 52 | if(_capacity < SSO) { 53 | char _temp[SSO]; 54 | memory::copy(_temp, _text, SSO); 55 | _data = memory::allocate(_capacity = capacity + 1); 56 | memory::copy(_data, _temp, SSO); 57 | } else { 58 | _data = memory::resize(_data, _capacity = capacity + 1); 59 | } 60 | return *this; 61 | } 62 | 63 | inline auto string::resize(uint size) -> type& { 64 | reserve(size); 65 | get()[_size = size] = 0; 66 | return *this; 67 | } 68 | 69 | inline auto string::operator=(const string& source) -> type& { 70 | if(&source == this) return *this; 71 | reset(); 72 | if(source._capacity >= SSO) { 73 | _data = memory::allocate(source._capacity + 1); 74 | _capacity = source._capacity; 75 | _size = source._size; 76 | memory::copy(_data, source._data, source._size + 1); 77 | } else { 78 | memory::copy(_text, source._text, SSO); 79 | _capacity = SSO - 1; 80 | _size = source._size; 81 | } 82 | return *this; 83 | } 84 | 85 | inline auto string::operator=(string&& source) -> type& { 86 | if(&source == this) return *this; 87 | reset(); 88 | memory::copy(this, &source, sizeof(string)); 89 | source._data = nullptr; 90 | source._capacity = SSO - 1; 91 | source._size = 0; 92 | return *this; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /string/core.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //only allocators may access _data or modify _size and _capacity 4 | //all other functions must use data(), size(), capacity() 5 | 6 | #if defined(NALL_STRING_ALLOCATOR_ADAPTIVE) 7 | #include 8 | #elif defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE) 9 | #include 10 | #elif defined(NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION) 11 | #include 12 | #elif defined(NALL_STRING_ALLOCATOR_VECTOR) 13 | #include 14 | #endif 15 | 16 | namespace nall { 17 | 18 | inline auto string::operator[](uint position) const -> const char& { 19 | #ifdef DEBUG 20 | struct out_of_bounds {}; 21 | if(position >= size() + 1) throw out_of_bounds{}; 22 | #endif 23 | return data()[position]; 24 | } 25 | 26 | inline auto string::operator()(uint position, char fallback) const -> char { 27 | if(position >= size() + 1) return fallback; 28 | return data()[position]; 29 | } 30 | 31 | template inline auto string::assign(P&&... p) -> string& { 32 | resize(0); 33 | return append(forward

(p)...); 34 | } 35 | 36 | template inline auto string::prepend(const T& value, P&&... p) -> string& { 37 | if constexpr(sizeof...(p)) prepend(forward

(p)...); 38 | return _prepend(make_string(value)); 39 | } 40 | 41 | template inline auto string::prepend(const nall::string_format& value, P&&... p) -> string& { 42 | if constexpr(sizeof...(p)) prepend(forward

(p)...); 43 | return format(value); 44 | } 45 | 46 | template inline auto string::_prepend(const stringify& source) -> string& { 47 | resize(source.size() + size()); 48 | memory::move(get() + source.size(), get(), size() - source.size()); 49 | memory::copy(get(), source.data(), source.size()); 50 | return *this; 51 | } 52 | 53 | template inline auto string::append(const T& value, P&&... p) -> string& { 54 | _append(make_string(value)); 55 | if constexpr(sizeof...(p) > 0) append(forward

(p)...); 56 | return *this; 57 | } 58 | 59 | template inline auto string::append(const nall::string_format& value, P&&... p) -> string& { 60 | format(value); 61 | if constexpr(sizeof...(p)) append(forward

(p)...); 62 | return *this; 63 | } 64 | 65 | template inline auto string::_append(const stringify& source) -> string& { 66 | resize(size() + source.size()); 67 | memory::copy(get() + size() - source.size(), source.data(), source.size()); 68 | return *this; 69 | } 70 | 71 | inline auto string::length() const -> uint { 72 | return strlen(data()); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /encode/huffman.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Encode { 4 | 5 | inline auto Huffman(array_view input) -> vector { 6 | vector output; 7 | for(uint byte : range(8)) output.append(input.size() >> byte * 8); 8 | 9 | struct Node { 10 | uint frequency = 0; 11 | uint parent = 0; 12 | uint lhs = 0; 13 | uint rhs = 0; 14 | }; 15 | array nodes; 16 | for(uint offset : range(input.size())) nodes[input[offset]].frequency++; 17 | 18 | uint count = 0; 19 | for(uint offset : range(511)) { 20 | if(nodes[offset].frequency) count++; 21 | else nodes[offset].parent = 511; 22 | } 23 | 24 | auto minimum = [&] { 25 | uint frequency = ~0, minimum = 511; 26 | for(uint index : range(511)) { 27 | if(!nodes[index].parent && nodes[index].frequency && nodes[index].frequency < frequency) { 28 | frequency = nodes[index].frequency; 29 | minimum = index; 30 | } 31 | } 32 | return minimum; 33 | }; 34 | 35 | //group the least two frequently used nodes until only one node remains 36 | uint index = 256; 37 | for(uint remaining = max(2, count); remaining >= 2; remaining--) { 38 | uint lhs = minimum(); 39 | nodes[lhs].parent = index; 40 | uint rhs = minimum(); 41 | nodes[rhs].parent = index; 42 | if(remaining == 2) index = nodes[lhs].parent = nodes[rhs].parent = 511; 43 | nodes[index].lhs = lhs; 44 | nodes[index].rhs = rhs; 45 | nodes[index].parent = 0; 46 | nodes[index].frequency = nodes[lhs].frequency + nodes[rhs].frequency; 47 | index++; 48 | } 49 | 50 | uint byte = 0, bits = 0; 51 | auto write = [&](bool bit) { 52 | byte = byte << 1 | bit; 53 | if(++bits == 8) output.append(byte), bits = 0; 54 | }; 55 | 56 | //only the upper half of the table is needed for decompression 57 | //the first 256 nodes are always treated as leaf nodes 58 | for(uint offset : range(256)) { 59 | for(uint index : reverse(range(9))) write(nodes[256 + offset].lhs >> index & 1); 60 | for(uint index : reverse(range(9))) write(nodes[256 + offset].rhs >> index & 1); 61 | } 62 | 63 | for(uint byte : input) { 64 | uint node = byte, length = 0; 65 | uint256_t sequence = 0; 66 | //traversing the array produces the bitstream in reverse order 67 | do { 68 | uint parent = nodes[node].parent; 69 | bool bit = nodes[nodes[node].parent].rhs == node; 70 | sequence = sequence << 1 | bit; 71 | length++; 72 | node = parent; 73 | } while(node != 511); 74 | //output the generated bits in the correct order 75 | for(uint index : range(length)) { 76 | write(sequence >> index & 1); 77 | } 78 | } 79 | while(bits) write(0); 80 | 81 | return output; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /merge-sort.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | //class: merge sort 7 | //average: O(n log n) 8 | //worst: O(n log n) 9 | //memory: O(n) 10 | //stack: O(log n) 11 | //stable?: yes 12 | 13 | //note: merge sort was chosen over quick sort, because: 14 | //* it is a stable sort 15 | //* it lacks O(n^2) worst-case overhead 16 | //* it usually runs faster than quick sort anyway 17 | 18 | //note: insertion sort is generally more performant than selection sort 19 | #define NALL_MERGE_SORT_INSERTION 20 | //#define NALL_MERGE_SORT_SELECTION 21 | 22 | namespace nall { 23 | 24 | template auto sort(T list[], uint size, const Comparator& lessthan) -> void { 25 | if(size <= 1) return; //nothing to sort 26 | 27 | //sort smaller blocks using an O(n^2) algorithm (which for small sizes, increases performance) 28 | if(size < 64) { 29 | //insertion sort requires a copy (via move construction) 30 | #if defined(NALL_MERGE_SORT_INSERTION) 31 | for(int i = 1, j; i < size; i++) { 32 | T copy(move(list[i])); 33 | for(j = i - 1; j >= 0; j--) { 34 | if(!lessthan(copy, list[j])) break; 35 | list[j + 1] = move(list[j]); 36 | } 37 | list[j + 1] = move(copy); 38 | } 39 | //selection sort requires a swap 40 | #elif defined(NALL_MERGE_SORT_SELECTION) 41 | for(uint i = 0; i < size; i++) { 42 | uint min = i; 43 | for(uint j = i + 1; j < size; j++) { 44 | if(lessthan(list[j], list[min])) min = j; 45 | } 46 | if(min != i) swap(list[i], list[min]); 47 | } 48 | #endif 49 | return; 50 | } 51 | 52 | //split list in half and recursively sort both 53 | uint middle = size / 2; 54 | sort(list, middle, lessthan); 55 | sort(list + middle, size - middle, lessthan); 56 | 57 | //left and right are sorted here; perform merge sort 58 | //use placement new to avoid needing T to be default-constructable 59 | auto buffer = memory::allocate(size); 60 | uint offset = 0, left = 0, right = middle; 61 | while(left < middle && right < size) { 62 | if(!lessthan(list[right], list[left])) { 63 | new(buffer + offset++) T(move(list[left++])); 64 | } else { 65 | new(buffer + offset++) T(move(list[right++])); 66 | } 67 | } 68 | while(left < middle) new(buffer + offset++) T(move(list[left++])); 69 | while(right < size ) new(buffer + offset++) T(move(list[right++])); 70 | 71 | for(uint i = 0; i < size; i++) { 72 | list[i] = move(buffer[i]); 73 | buffer[i].~T(); 74 | } 75 | memory::free(buffer); 76 | } 77 | 78 | template auto sort(T list[], uint size) -> void { 79 | return sort(list, size, [](const T& l, const T& r) { return l < r; }); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /image/blend.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline auto image::impose(blend mode, uint targetX, uint targetY, image source, uint sourceX, uint sourceY, uint sourceWidth, uint sourceHeight) -> void { 6 | source.transform(_endian, _depth, _alpha.mask(), _red.mask(), _green.mask(), _blue.mask()); 7 | 8 | for(uint y = 0; y < sourceHeight; y++) { 9 | const uint8_t* sp = source._data + source.pitch() * (sourceY + y) + source.stride() * sourceX; 10 | uint8_t* dp = _data + pitch() * (targetY + y) + stride() * targetX; 11 | for(uint x = 0; x < sourceWidth; x++) { 12 | uint64_t sourceColor = source.read(sp); 13 | uint64_t targetColor = read(dp); 14 | 15 | int64_t sa = (sourceColor & _alpha.mask()) >> _alpha.shift(); 16 | int64_t sr = (sourceColor & _red.mask() ) >> _red.shift(); 17 | int64_t sg = (sourceColor & _green.mask()) >> _green.shift(); 18 | int64_t sb = (sourceColor & _blue.mask() ) >> _blue.shift(); 19 | 20 | int64_t da = (targetColor & _alpha.mask()) >> _alpha.shift(); 21 | int64_t dr = (targetColor & _red.mask() ) >> _red.shift(); 22 | int64_t dg = (targetColor & _green.mask()) >> _green.shift(); 23 | int64_t db = (targetColor & _blue.mask() ) >> _blue.shift(); 24 | 25 | uint64_t a, r, g, b; 26 | 27 | switch(mode) { 28 | case blend::add: 29 | a = max(sa, da); 30 | r = min(_red.mask() >> _red.shift(), ((sr * sa) >> _alpha.depth()) + ((dr * da) >> _alpha.depth())); 31 | g = min(_green.mask() >> _green.shift(), ((sg * sa) >> _alpha.depth()) + ((dg * da) >> _alpha.depth())); 32 | b = min(_blue.mask() >> _blue.shift(), ((sb * sa) >> _alpha.depth()) + ((db * da) >> _alpha.depth())); 33 | break; 34 | 35 | case blend::sourceAlpha: 36 | a = max(sa, da); 37 | r = dr + (((sr - dr) * sa) >> _alpha.depth()); 38 | g = dg + (((sg - dg) * sa) >> _alpha.depth()); 39 | b = db + (((sb - db) * sa) >> _alpha.depth()); 40 | break; 41 | 42 | case blend::sourceColor: 43 | a = sa; 44 | r = sr; 45 | g = sg; 46 | b = sb; 47 | break; 48 | 49 | case blend::targetAlpha: 50 | a = max(sa, da); 51 | r = sr + (((dr - sr) * da) >> _alpha.depth()); 52 | g = sg + (((dg - sg) * da) >> _alpha.depth()); 53 | b = sb + (((db - sb) * da) >> _alpha.depth()); 54 | break; 55 | 56 | case blend::targetColor: 57 | a = da; 58 | r = dr; 59 | g = dg; 60 | b = db; 61 | break; 62 | } 63 | 64 | write(dp, (a << _alpha.shift()) | (r << _red.shift()) | (g << _green.shift()) | (b << _blue.shift())); 65 | sp += source.stride(); 66 | dp += stride(); 67 | } 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /string/find.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline auto string::contains(string_view characters) const -> maybe { 6 | for(uint x : range(size())) { 7 | for(char y : characters) { 8 | if(operator[](x) == y) return x; 9 | } 10 | } 11 | return nothing; 12 | } 13 | 14 | template inline auto string::_find(int offset, string_view source) const -> maybe { 15 | if(source.size() == 0) return nothing; 16 | auto p = data(); 17 | for(uint n = offset, quoted = 0; n < size();) { 18 | if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } 19 | if(_compare(p + n, size() - n, source.data(), source.size())) { n++; continue; } 20 | return n - offset; 21 | } 22 | return nothing; 23 | } 24 | 25 | inline auto string::find(string_view source) const -> maybe { return _find<0, 0>(0, source); } 26 | inline auto string::ifind(string_view source) const -> maybe { return _find<1, 0>(0, source); } 27 | inline auto string::qfind(string_view source) const -> maybe { return _find<0, 1>(0, source); } 28 | inline auto string::iqfind(string_view source) const -> maybe { return _find<1, 1>(0, source); } 29 | 30 | inline auto string::findFrom(int offset, string_view source) const -> maybe { return _find<0, 0>(offset, source); } 31 | inline auto string::ifindFrom(int offset, string_view source) const -> maybe { return _find<1, 0>(offset, source); } 32 | 33 | inline auto string::findNext(int offset, string_view source) const -> maybe { 34 | if(source.size() == 0) return nothing; 35 | for(int n = offset + 1; n < size(); n++) { 36 | if(memory::compare(data() + n, size() - n, source.data(), source.size()) == 0) return n; 37 | } 38 | return nothing; 39 | } 40 | 41 | inline auto string::ifindNext(int offset, string_view source) const -> maybe { 42 | if(source.size() == 0) return nothing; 43 | for(int n = offset + 1; n < size(); n++) { 44 | if(memory::icompare(data() + n, size() - n, source.data(), source.size()) == 0) return n; 45 | } 46 | return nothing; 47 | } 48 | 49 | inline auto string::findPrevious(int offset, string_view source) const -> maybe { 50 | if(source.size() == 0) return nothing; 51 | for(int n = offset - 1; n >= 0; n--) { 52 | if(memory::compare(data() + n, size() - n, source.data(), source.size()) == 0) return n; 53 | } 54 | return nothing; 55 | } 56 | 57 | inline auto string::ifindPrevious(int offset, string_view source) const -> maybe { 58 | if(source.size() == 0) return nothing; 59 | for(int n = offset - 1; n >= 0; n--) { 60 | if(memory::icompare(data() + n, size() - n, source.data(), source.size()) == 0) return n; 61 | } 62 | return nothing; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /encode/lzsa.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace nall::Encode { 10 | 11 | inline auto LZSA(array_view input) -> vector { 12 | vector output; 13 | for(uint byte : range(8)) output.append(input.size() >> byte * 8); 14 | 15 | auto suffixArray = SuffixArray(input).lpf(); 16 | uint index = 0; 17 | vector flags; 18 | vector literals; 19 | vector stringLengths; 20 | vector stringOffsets; 21 | 22 | uint byte = 0, bits = 0; 23 | auto flagWrite = [&](bool bit) { 24 | byte = byte << 1 | bit; 25 | if(++bits == 8) flags.append(byte), bits = 0; 26 | }; 27 | 28 | auto literalWrite = [&](uint8_t literal) { 29 | literals.append(literal); 30 | }; 31 | 32 | auto lengthWrite = [&](uint64_t length) { 33 | if(length < 1 << 7) length = length << 1 | 0b1; 34 | else if(length < 1 << 14) length = length << 2 | 0b10; 35 | else if(length < 1 << 21) length = length << 3 | 0b100; 36 | else if(length < 1 << 28) length = length << 4 | 0b1000; 37 | else /*length < 1 << 35*/length = length << 5 | 0b10000; 38 | while(length) stringLengths.append(length), length >>= 8; 39 | }; 40 | 41 | auto offsetWrite = [&](uint offset) { 42 | stringOffsets.append(offset >> 0); if(index < 1 << 8) return; 43 | stringOffsets.append(offset >> 8); if(index < 1 << 16) return; 44 | stringOffsets.append(offset >> 16); if(index < 1 << 24) return; 45 | stringOffsets.append(offset >> 24); 46 | }; 47 | 48 | while(index < input.size()) { 49 | int length, offset; 50 | suffixArray.previous(length, offset, index); 51 | 52 | /* for(uint ahead = 1; ahead <= 2; ahead++) { 53 | int aheadLength, aheadOffset; 54 | suffixArray.previous(aheadLength, aheadOffset, index + ahead); 55 | if(aheadLength > length && aheadOffset >= 0) { 56 | length = 0; 57 | break; 58 | } 59 | } */ 60 | 61 | if(length < 6 || offset < 0) { 62 | flagWrite(0); 63 | literalWrite(input[index++]); 64 | } else { 65 | flagWrite(1); 66 | lengthWrite(length - 6); 67 | offsetWrite(index - offset); 68 | index += length; 69 | } 70 | } 71 | while(bits) flagWrite(0); 72 | 73 | auto save = [&](const vector& buffer) { 74 | for(uint byte : range(8)) output.append(buffer.size() >> byte * 8); 75 | output.append(buffer); 76 | }; 77 | 78 | save(Encode::Huffman(flags)); 79 | save(Encode::Huffman(literals)); 80 | save(Encode::Huffman(stringLengths)); 81 | save(Encode::Huffman(stringOffsets)); 82 | 83 | return output; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /any.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace nall { 7 | 8 | struct any { 9 | any() = default; 10 | any(const any& source) { operator=(source); } 11 | any(any&& source) { operator=(move(source)); } 12 | template any(const T& value) { operator=(value); } 13 | ~any() { reset(); } 14 | 15 | explicit operator bool() const { return container; } 16 | auto reset() -> void { if(container) { delete container; container = nullptr; } } 17 | 18 | auto type() const -> const std::type_info& { 19 | return container ? container->type() : typeid(void); 20 | } 21 | 22 | template auto is() const -> bool { 23 | return type() == typeid(typename remove_reference::type); 24 | } 25 | 26 | template auto get() -> T& { 27 | if(!is()) throw; 28 | return static_cast::type>*>(container)->value; 29 | } 30 | 31 | template auto get() const -> const T& { 32 | if(!is()) throw; 33 | return static_cast::type>*>(container)->value; 34 | } 35 | 36 | template auto get(const T& fallback) const -> const T& { 37 | if(!is()) return fallback; 38 | return static_cast::type>*>(container)->value; 39 | } 40 | 41 | template auto operator=(const T& value) -> any& { 42 | using auto_t = typename conditional::value, typename remove_extent::type>::type*, T>::type; 43 | 44 | if(type() == typeid(auto_t)) { 45 | static_cast*>(container)->value = (auto_t)value; 46 | } else { 47 | if(container) delete container; 48 | container = new holder((auto_t)value); 49 | } 50 | 51 | return *this; 52 | } 53 | 54 | auto operator=(const any& source) -> any& { 55 | if(container) { delete container; container = nullptr; } 56 | if(source.container) container = source.container->copy(); 57 | return *this; 58 | } 59 | 60 | auto operator=(any&& source) -> any& { 61 | if(container) delete container; 62 | container = source.container; 63 | source.container = nullptr; 64 | return *this; 65 | } 66 | 67 | private: 68 | struct placeholder { 69 | virtual ~placeholder() = default; 70 | virtual auto type() const -> const std::type_info& = 0; 71 | virtual auto copy() const -> placeholder* = 0; 72 | }; 73 | placeholder* container = nullptr; 74 | 75 | template struct holder : placeholder { 76 | holder(const T& value) : value(value) {} 77 | auto type() const -> const std::type_info& { return typeid(T); } 78 | auto copy() const -> placeholder* { return new holder(value); } 79 | T value; 80 | }; 81 | }; 82 | 83 | } 84 | -------------------------------------------------------------------------------- /bit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall { 6 | 7 | template inline auto uclamp(T x) -> uint64_t { 8 | enum : uint64_t { b = 1ull << (bits - 1), y = b * 2 - 1 }; 9 | if constexpr(is_unsigned_v) { 10 | return y + ((x - y) & -(x < y)); //min(x, y); 11 | } 12 | if constexpr(is_signed_v) { 13 | return x < 0 ? 0 : x > y ? y : x; 14 | } 15 | } 16 | 17 | template inline auto uclip(uint64_t x) -> uint64_t { 18 | enum : uint64_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; 19 | return (x & m); 20 | } 21 | 22 | template inline auto sclamp(int64_t x) -> int64_t { 23 | enum : int64_t { b = 1ull << (bits - 1), m = b - 1 }; 24 | return (x > m) ? m : (x < -b) ? -b : x; 25 | } 26 | 27 | template inline auto sclip(int64_t x) -> int64_t { 28 | enum : uint64_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; 29 | return ((x & m) ^ b) - b; 30 | } 31 | 32 | namespace bit { 33 | constexpr inline auto mask(const char* s, uint64_t sum = 0) -> uint64_t { 34 | return ( 35 | *s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) : 36 | *s == ' ' || *s == '_' ? mask(s + 1, sum) : 37 | *s ? mask(s + 1, sum << 1) : 38 | sum 39 | ); 40 | } 41 | 42 | constexpr inline auto test(const char* s, uint64_t sum = 0) -> uint64_t { 43 | return ( 44 | *s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) : 45 | *s == ' ' || *s == '_' ? test(s + 1, sum) : 46 | *s ? test(s + 1, sum << 1) : 47 | sum 48 | ); 49 | } 50 | 51 | //lowest(0b1110) == 0b0010 52 | constexpr inline auto lowest(const uint64_t x) -> uint64_t { 53 | return x & -x; 54 | } 55 | 56 | //clear_lowest(0b1110) == 0b1100 57 | constexpr inline auto clearLowest(const uint64_t x) -> uint64_t { 58 | return x & (x - 1); 59 | } 60 | 61 | //set_lowest(0b0101) == 0b0111 62 | constexpr inline auto setLowest(const uint64_t x) -> uint64_t { 63 | return x | (x + 1); 64 | } 65 | 66 | //count number of bits set in a byte 67 | constexpr inline auto count(uint64_t x) -> uint { 68 | uint count = 0; 69 | while(x) x &= x - 1, count++; //clear the least significant bit 70 | return count; 71 | } 72 | 73 | //return index of the first bit set (or zero of no bits are set) 74 | //first(0b1000) == 3 75 | constexpr inline auto first(uint64_t x) -> uint { 76 | uint first = 0; 77 | while(x) { if(x & 1) break; x >>= 1; first++; } 78 | return first; 79 | } 80 | 81 | //round up to next highest single bit: 82 | //round(15) == 16, round(16) == 16, round(17) == 32 83 | constexpr inline auto round(uint64_t x) -> uint64_t { 84 | if((x & (x - 1)) == 0) return x; 85 | while(x & (x - 1)) x &= x - 1; 86 | return x << 1; 87 | } 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /location.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall::Location { 6 | 7 | // (/parent/child.type/) 8 | // (/parent/child.type/)name.type 9 | inline auto path(string_view self) -> string { 10 | const char* p = self.data() + self.size() - 1; 11 | for(int offset = self.size() - 1; offset >= 0; offset--, p--) { 12 | if(*p == '/') return slice(self, 0, offset + 1); 13 | } 14 | return ""; //no path found 15 | } 16 | 17 | // /parent/child.type/() 18 | // /parent/child.type/(name.type) 19 | inline auto file(string_view self) -> string { 20 | const char* p = self.data() + self.size() - 1; 21 | for(int offset = self.size() - 1; offset >= 0; offset--, p--) { 22 | if(*p == '/') return slice(self, offset + 1); 23 | } 24 | return self; //no path found 25 | } 26 | 27 | // (/parent/)child.type/ 28 | // (/parent/child.type/)name.type 29 | inline auto dir(string_view self) -> string { 30 | const char* p = self.data() + self.size() - 1, *last = p; 31 | for(int offset = self.size() - 1; offset >= 0; offset--, p--) { 32 | if(*p == '/' && p == last) continue; 33 | if(*p == '/') return slice(self, 0, offset + 1); 34 | } 35 | return ""; //no path found 36 | } 37 | 38 | // /parent/(child.type/) 39 | // /parent/child.type/(name.type) 40 | inline auto base(string_view self) -> string { 41 | const char* p = self.data() + self.size() - 1, *last = p; 42 | for(int offset = self.size() - 1; offset >= 0; offset--, p--) { 43 | if(*p == '/' && p == last) continue; 44 | if(*p == '/') return slice(self, offset + 1); 45 | } 46 | return self; //no path found 47 | } 48 | 49 | // /parent/(child).type/ 50 | // /parent/child.type/(name).type 51 | inline auto prefix(string_view self) -> string { 52 | const char* p = self.data() + self.size() - 1, *last = p; 53 | for(int offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) { 54 | if(*p == '/' && p == last) continue; 55 | if(*p == '/') return slice(self, offset + 1, (suffix >= 0 ? suffix : self.size()) - offset - 1).trimRight("/"); 56 | if(*p == '.' && suffix == -1) { suffix = offset; continue; } 57 | if(offset == 0) return slice(self, offset, suffix).trimRight("/"); 58 | } 59 | return ""; //no prefix found 60 | } 61 | 62 | // /parent/child(.type)/ 63 | // /parent/child.type/name(.type) 64 | inline auto suffix(string_view self) -> string { 65 | const char* p = self.data() + self.size() - 1, *last = p; 66 | for(int offset = self.size() - 1; offset >= 0; offset--, p--) { 67 | if(*p == '/' && p == last) continue; 68 | if(*p == '/') break; 69 | if(*p == '.') return slice(self, offset).trimRight("/"); 70 | } 71 | return ""; //no suffix found 72 | } 73 | 74 | inline auto notsuffix(string_view self) -> string { 75 | return {path(self), prefix(self)}; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /elliptic-curve/modulo25519-reference.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //warning: this implementation leaks side-channel information 4 | //use modulo25519-optimized.hpp in production 5 | 6 | #include 7 | 8 | namespace nall::EllipticCurve { 9 | 10 | static const uint256_t P = (1_u256 << 255) - 19; 11 | 12 | struct Modulo25519 { 13 | Modulo25519() = default; 14 | Modulo25519(const Modulo25519& source) : value(source.value) {} 15 | template Modulo25519(const T& value) : value(value) {} 16 | explicit operator bool() const { return (bool)value; } 17 | auto operator()() const -> uint256_t { return value; } 18 | 19 | private: 20 | uint256_t value; 21 | }; 22 | 23 | inline auto operator-(const Modulo25519& lhs) -> Modulo25519 { 24 | return P - lhs(); 25 | } 26 | 27 | inline auto operator+(const Modulo25519& lhs, const Modulo25519& rhs) -> Modulo25519 { 28 | uint512_t value = (uint512_t)lhs() + rhs(); 29 | if(value >= P) value -= P; 30 | return value; 31 | } 32 | 33 | inline auto operator-(const Modulo25519& lhs, const Modulo25519& rhs) -> Modulo25519 { 34 | uint512_t value = (uint512_t)lhs(); 35 | if(value < rhs()) value += P; 36 | return uint256_t(value - rhs()); 37 | } 38 | 39 | inline auto operator*(const Modulo25519& lhs, const Modulo25519& rhs) -> Modulo25519 { 40 | static const BarrettReduction<256> P{EllipticCurve::P}; 41 | uint256_t hi, lo; 42 | mul(lhs(), rhs(), hi, lo); 43 | return uint512_t{hi, lo} % P; 44 | } 45 | 46 | inline auto operator&(const Modulo25519& lhs, uint256_t rhs) -> uint256_t { 47 | return lhs() & rhs; 48 | } 49 | 50 | inline auto square(const Modulo25519& lhs) -> Modulo25519 { 51 | static const BarrettReduction<256> P{EllipticCurve::P}; 52 | uint256_t hi, lo; 53 | square(lhs(), hi, lo); 54 | return uint512_t{hi, lo} % P; 55 | } 56 | 57 | inline auto exponentiate(const Modulo25519& lhs, uint256_t exponent) -> Modulo25519 { 58 | if(exponent == 0) return 1; 59 | Modulo25519 value = square(exponentiate(lhs, exponent >> 1)); 60 | if(exponent & 1) value = value * lhs; 61 | return value; 62 | } 63 | 64 | inline auto reciprocal(const Modulo25519& lhs) -> Modulo25519 { 65 | return exponentiate(lhs, P - 2); 66 | } 67 | 68 | inline auto squareRoot(const Modulo25519& lhs) -> Modulo25519 { 69 | static const Modulo25519 I = exponentiate(Modulo25519(2), P - 1 >> 2); //I = sqrt(-1) 70 | Modulo25519 value = exponentiate(lhs, P + 3 >> 3); 71 | if(square(value) - lhs) value = value * I; 72 | if(value & 1) value = -value; 73 | return value; 74 | } 75 | 76 | inline auto cmove(bool condition, Modulo25519& lhs, const Modulo25519& rhs) -> void { 77 | if(condition) lhs = rhs; 78 | } 79 | 80 | inline auto cswap(bool condition, Modulo25519& lhs, Modulo25519& rhs) -> void { 81 | if(condition) swap(lhs, rhs); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /nall.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //include the most common nall headers with one statement 4 | //does not include the most obscure components with high cost and low usage 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | //#include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include //todo: compilation errors when included earlier 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | 85 | #if defined(PLATFORM_WINDOWS) 86 | #include 87 | #include 88 | #endif 89 | 90 | #if defined(API_POSIX) 91 | #include 92 | #endif 93 | -------------------------------------------------------------------------------- /array-span.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall { 6 | 7 | template struct array_span : array_view { 8 | using type = array_span; 9 | using super = array_view; 10 | 11 | array_span() { 12 | super::_data = nullptr; 13 | super::_size = 0; 14 | } 15 | 16 | array_span(nullptr_t) { 17 | super::_data = nullptr; 18 | super::_size = 0; 19 | } 20 | 21 | array_span(void* data, uint64_t size) { 22 | super::_data = (T*)data; 23 | super::_size = (int)size; 24 | } 25 | 26 | operator T*() { return (T*)super::operator const T*(); } 27 | 28 | auto operator[](uint index) -> T& { return (T&)super::operator[](index); } 29 | 30 | template auto data() -> U* { return (U*)super::_data; } 31 | template auto data() const -> const U* { return (const U*)super::_data; } 32 | 33 | auto begin() -> iterator { return {(T*)super::_data, (uint)0}; } 34 | auto end() -> iterator { return {(T*)super::_data, (uint)super::_size}; } 35 | 36 | auto rbegin() -> reverse_iterator { return {(T*)super::_data, (uint)super::_size - 1}; } 37 | auto rend() -> reverse_iterator { return {(T*)super::_data, (uint)-1}; } 38 | 39 | auto write(T value) -> void { 40 | operator[](0) = value; 41 | super::_data++; 42 | super::_size--; 43 | } 44 | 45 | auto span(uint offset, uint length) const -> type { 46 | #ifdef DEBUG 47 | struct out_of_bounds {}; 48 | if(offset + length >= super::_size) throw out_of_bounds{}; 49 | #endif 50 | return {super::_data + offset, length}; 51 | } 52 | 53 | //array_span specializations 54 | template auto writel(U value, uint size) -> void; 55 | template auto writem(U value, uint size) -> void; 56 | template auto writevn(U value, uint size) -> void; 57 | template auto writevi(U value, uint size) -> void; 58 | }; 59 | 60 | //array_span 61 | 62 | template<> inline auto array_span::write(uint8_t value) -> void { 63 | operator[](0) = value; 64 | _data++; 65 | _size--; 66 | } 67 | 68 | template<> template inline auto array_span::writel(U value, uint size) -> void { 69 | for(uint byte : range(size)) write(value >> byte * 8); 70 | } 71 | 72 | template<> template inline auto array_span::writem(U value, uint size) -> void { 73 | for(uint byte : reverse(range(size))) write(value >> byte * 8); 74 | } 75 | 76 | template<> template inline auto array_span::writevn(U value, uint size) -> void { 77 | while(true) { 78 | auto byte = value & 0x7f; 79 | value >>= 7; 80 | if(value == 0) return write(0x80 | byte); 81 | write(byte); 82 | value--; 83 | } 84 | } 85 | 86 | template<> template inline auto array_span::writevi(U value, uint size) -> void { 87 | bool negate = value < 0; 88 | if(negate) value = ~value; 89 | value = value << 1 | negate; 90 | writevn(value); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /iterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template struct iterator { 6 | iterator(T* self, uint64_t offset) : _self(self), _offset(offset) {} 7 | auto operator*() -> T& { return _self[_offset]; } 8 | auto operator!=(const iterator& source) const -> bool { return _offset != source._offset; } 9 | auto operator++() -> iterator& { return _offset++, *this; } 10 | auto offset() const -> uint64_t { return _offset; } 11 | 12 | private: 13 | T* _self; 14 | uint64_t _offset; 15 | }; 16 | 17 | template struct iterator_const { 18 | iterator_const(const T* self, uint64_t offset) : _self(self), _offset(offset) {} 19 | auto operator*() -> const T& { return _self[_offset]; } 20 | auto operator!=(const iterator_const& source) const -> bool { return _offset != source._offset; } 21 | auto operator++() -> iterator_const& { return _offset++, *this; } 22 | auto offset() const -> uint64_t { return _offset; } 23 | 24 | private: 25 | const T* _self; 26 | uint64_t _offset; 27 | }; 28 | 29 | template struct reverse_iterator { 30 | reverse_iterator(T* self, uint64_t offset) : _self(self), _offset(offset) {} 31 | auto operator*() -> T& { return _self[_offset]; } 32 | auto operator!=(const reverse_iterator& source) const -> bool { return _offset != source._offset; } 33 | auto operator++() -> reverse_iterator& { return _offset--, *this; } 34 | auto offset() const -> uint64_t { return _offset; } 35 | 36 | private: 37 | T* _self; 38 | uint64_t _offset; 39 | }; 40 | 41 | template struct reverse_iterator_const { 42 | reverse_iterator_const(const T* self, uint64_t offset) : _self(self), _offset(offset) {} 43 | auto operator*() -> const T& { return _self[_offset]; } 44 | auto operator!=(const reverse_iterator_const& source) const -> bool { return _offset != source._offset; } 45 | auto operator++() -> reverse_iterator_const& { return _offset--, *this; } 46 | auto offset() const -> uint64_t { return _offset; } 47 | 48 | private: 49 | const T* _self; 50 | uint64_t _offset; 51 | }; 52 | 53 | //std::rbegin(), std::rend() is missing from GCC 4.9; which I still target 54 | 55 | template auto rbegin(T (&array)[Size]) { return reverse_iterator{array, Size - 1}; } 56 | template auto rend(T (&array)[Size]) { return reverse_iterator{array, (uint64_t)-1}; } 57 | 58 | template auto rbegin(T& self) { return self.rbegin(); } 59 | template auto rend(T& self) { return self.rend(); } 60 | 61 | template struct reverse_wrapper { 62 | auto begin() { return rbegin(_self); } 63 | auto end() { return rend(_self); } 64 | 65 | auto begin() const { return rbegin(_self); } 66 | auto end() const { return rend(_self); } 67 | 68 | T _self; 69 | }; 70 | 71 | template auto reverse(T& object) -> reverse_wrapper { 72 | return {object}; 73 | } 74 | 75 | template auto reverse(T&& object) -> reverse_wrapper { 76 | return {object}; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /beat/archive/create.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace nall::Beat::Archive { 7 | 8 | auto create(Container& container, string name) -> vector { 9 | auto& metadata = container.metadata; 10 | metadata = {}; 11 | metadata.append("archive: ", Location::file(name), "\n"); 12 | 13 | vector memory; 14 | 15 | container.sort(); 16 | for(auto& node : container.nodes) { 17 | if(node->isFile()) { 18 | node->offset = memory.size(); 19 | memory.append(node->memory); 20 | } 21 | metadata.append(node->metadata()); 22 | } 23 | 24 | metadata.append(" size: ", memory.size(), "\n"); 25 | 26 | if(container.compression.type == "lzsa") { 27 | memory = Encode::LZSA(memory); 28 | metadata.append(" compression: lzsa\n"); 29 | metadata.append(" size: ", memory.size(), "\n"); 30 | } 31 | 32 | if(container.signature.type == "ed25519") { 33 | EllipticCurve::Ed25519 ed25519; 34 | container.signature.publicKey = ed25519.publicKey(container.signature.privateKey); 35 | container.signature.value = ed25519.sign(memory, container.signature.privateKey); 36 | 37 | metadata.append(" signature: ed25519\n"); 38 | metadata.append(" publicKey: ", Encode::Base<57>(container.signature.publicKey), "\n"); 39 | metadata.append(" value: ", Encode::Base<57>(container.signature.value), "\n"); 40 | } 41 | 42 | for(auto& byte : metadata) memory.append(byte); 43 | memory.appendl((uint64_t)metadata.size(), 8); 44 | 45 | auto sha256 = Hash::SHA256(memory).value(); 46 | memory.appendl((uint256_t)sha256, 32); 47 | 48 | memory.append('B'); 49 | memory.append('P'); 50 | memory.append('A'); 51 | memory.append('1'); 52 | 53 | if(container.encryption.type == "xchacha20") { 54 | Cipher::XChaCha20 xchacha20{container.encryption.privateKey, container.encryption.nonce}; 55 | memory = xchacha20.encrypt(memory); 56 | 57 | metadata = {}; 58 | metadata.append("archive\n"); 59 | metadata.append(" encryption: xchacha20\n"); 60 | metadata.append(" nonce: ", Encode::Base<57>(container.encryption.nonce), "\n"); 61 | 62 | if(container.signature.type == "ed25519") { 63 | EllipticCurve::Ed25519 ed25519; 64 | container.signature.value = ed25519.sign(memory, container.signature.privateKey); 65 | 66 | metadata.append(" signature: ed25519\n"); 67 | //metadata.append(" publicKey: ", Encode::Base<57>(container.signature.publicKey), "\n"); 68 | metadata.append(" value: ", Encode::Base<57>(container.signature.value), "\n"); 69 | } 70 | 71 | for(auto& byte : metadata) memory.append(byte ^ memory.size()); 72 | memory.appendl((uint64_t)metadata.size() | 1ull << 63, 8); 73 | 74 | auto sha256 = Hash::SHA256(memory).value(); 75 | memory.appendl((uint256_t)sha256, 32); 76 | 77 | memory.append('B'); 78 | memory.append('P'); 79 | memory.append('A'); 80 | memory.append('1'); 81 | } 82 | 83 | return memory; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /string/eval/literal.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Eval { 4 | 5 | inline auto isLiteral(const char*& s) -> bool { 6 | char n = s[0]; 7 | return (n >= 'A' && n <= 'Z') 8 | || (n >= 'a' && n <= 'z') 9 | || (n >= '0' && n <= '9') 10 | || (n == '%' || n == '$' || n == '_' || n == '.') 11 | || (n == '\'' || n == '\"'); 12 | } 13 | 14 | inline auto literalNumber(const char*& s) -> string { 15 | const char* p = s; 16 | 17 | //binary 18 | if(p[0] == '%' || (p[0] == '0' && p[1] == 'b')) { 19 | uint prefix = 1 + (p[0] == '0'); 20 | p += prefix; 21 | while(p[0] == '\'' || p[0] == '0' || p[0] == '1') p++; 22 | if(p - s <= prefix) throw "invalid binary literal"; 23 | string result = slice(s, 0, p - s); 24 | s = p; 25 | return result; 26 | } 27 | 28 | //octal 29 | if(p[0] == '0' && p[1] == 'o') { 30 | uint prefix = 1 + (p[0] == '0'); 31 | p += prefix; 32 | while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '7')) p++; 33 | if(p - s <= prefix) throw "invalid octal literal"; 34 | string result = slice(s, 0, p - s); 35 | s = p; 36 | return result; 37 | } 38 | 39 | //hex 40 | if(p[0] == '$' || (p[0] == '0' && p[1] == 'x')) { 41 | uint prefix = 1 + (p[0] == '0'); 42 | p += prefix; 43 | while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9') || (p[0] >= 'A' && p[0] <= 'F') || (p[0] >= 'a' && p[0] <= 'f')) p++; 44 | if(p - s <= prefix) throw "invalid hex literal"; 45 | string result = slice(s, 0, p - s); 46 | s = p; 47 | return result; 48 | } 49 | 50 | //decimal 51 | while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9')) p++; 52 | if(p[0] != '.') { 53 | string result = slice(s, 0, p - s); 54 | s = p; 55 | return result; 56 | } 57 | 58 | //floating-point 59 | p++; 60 | while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9')) p++; 61 | string result = slice(s, 0, p - s); 62 | s = p; 63 | return result; 64 | } 65 | 66 | inline auto literalString(const char*& s) -> string { 67 | const char* p = s; 68 | char escape = *p++; 69 | 70 | while(p[0] && p[0] != escape) p++; 71 | if(*p++ != escape) throw "unclosed string literal"; 72 | 73 | string result = slice(s, 0, p - s); 74 | s = p; 75 | return result; 76 | } 77 | 78 | inline auto literalVariable(const char*& s) -> string { 79 | const char* p = s; 80 | 81 | while(p[0] == '_' || p[0] == '.' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || (p[0] >= '0' && p[0] <= '9')) p++; 82 | 83 | string result = slice(s, 0, p - s); 84 | s = p; 85 | return result; 86 | } 87 | 88 | inline auto literal(const char*& s) -> string { 89 | const char* p = s; 90 | 91 | if(p[0] >= '0' && p[0] <= '9') return literalNumber(s); 92 | if(p[0] == '%' || p[0] == '$') return literalNumber(s); 93 | if(p[0] == '\'' || p[0] == '\"') return literalString(s); 94 | if(p[0] == '_' || p[0] == '.' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')) return literalVariable(s); 95 | 96 | throw "invalid literal"; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /encode/bwt.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //burrows-wheeler transform 4 | 5 | #include 6 | 7 | namespace nall::Encode { 8 | 9 | /* 10 | A standard suffix array cannot produce a proper burrows-wheeler transform, due to rotations. 11 | 12 | Take the input string, "nall", this gives us: 13 | nall 14 | alln 15 | llna 16 | lnal 17 | 18 | If we suffix sort this, we produce: 19 | all => alln 20 | l => lnal 21 | ll => llna 22 | nall => nall 23 | 24 | If we sort this, we produce: 25 | alln 26 | llna 27 | lnal 28 | nall 29 | 30 | Thus, suffix sorting gives us "nlal" as the last column instead of "nall". 31 | This is because BWT rotates the input string, whereas suffix arrays sort the input string. 32 | 33 | Adding a 256th character terminator before sorting will not produce the desired result, either. 34 | A more complicated string such as "mississippi" will sort as "ssmppissiii" with terminator=256, 35 | and as "ipssmpissii" with terminator=0, alphabet=1..256, whereas we want "pssmipissii". 36 | 37 | Performing a merge sort to use a specialized comparison function that wraps suffixes is too slow at O(n log n). 38 | 39 | Producing a custom induced sort to handle rotations would be incredibly complicated, 40 | owing to the recursive nature of induced sorting, among other things. 41 | 42 | So instead, a temporary array is produced that contains the input suffix twice. 43 | This is then fed into the suffix array sort, and the doubled matches are filtered out. 44 | After this point, suffixes are sorted in their mirrored form, and the correct result can be derived 45 | 46 | The result of this is an O(2n) algorithm, which vastly outperforms a naive O(n log n) algorithm, 47 | but is still far from ideal. However, this will have to do until a better solution is devised. 48 | 49 | Although to be fair, BWT is inferior to the bijective BWT anyway, so it may not be worth the effort. 50 | */ 51 | 52 | inline auto BWT(array_view input) -> vector { 53 | auto size = input.size(); 54 | vector output; 55 | output.reserve(8 + 8 + size); 56 | for(uint byte : range(8)) output.append(size >> byte * 8); 57 | for(uint byte : range(8)) output.append(0x00); 58 | 59 | vector buffer; 60 | buffer.reserve(2 * size); 61 | for(uint offset : range(size)) buffer.append(input[offset]); 62 | for(uint offset : range(size)) buffer.append(input[offset]); 63 | 64 | auto suffixes = SuffixArray(buffer); 65 | 66 | vector prefixes; 67 | prefixes.reserve(size); 68 | 69 | for(uint offset : range(2 * size + 1)) { 70 | uint suffix = suffixes[offset]; 71 | if(suffix >= size) continue; //beyond the bounds of the original input string 72 | prefixes.append(suffix); 73 | } 74 | 75 | uint64_t root = 0; 76 | for(uint offset : range(size)) { 77 | uint suffix = prefixes[offset]; 78 | if(suffix == 0) root = offset, suffix = size; 79 | output.append(input[--suffix]); 80 | } 81 | for(uint byte : range(8)) output[8 + byte] = root >> byte * 8; 82 | 83 | return output; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /unique-pointer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template 6 | struct unique_pointer { 7 | template static auto create(P&&... p) { 8 | return unique_pointer{new T{forward

(p)...}}; 9 | } 10 | 11 | using type = T; 12 | T* pointer = nullptr; 13 | function deleter; 14 | 15 | unique_pointer(const unique_pointer&) = delete; 16 | auto operator=(const unique_pointer&) -> unique_pointer& = delete; 17 | 18 | unique_pointer(T* pointer = nullptr, const function& deleter = {}) : pointer(pointer), deleter(deleter) {} 19 | ~unique_pointer() { reset(); } 20 | 21 | auto operator=(T* source) -> unique_pointer& { 22 | reset(); 23 | pointer = source; 24 | return *this; 25 | } 26 | 27 | explicit operator bool() const { return pointer; } 28 | 29 | auto operator->() -> T* { return pointer; } 30 | auto operator->() const -> const T* { return pointer; } 31 | 32 | auto operator*() -> T& { return *pointer; } 33 | auto operator*() const -> const T& { return *pointer; } 34 | 35 | auto operator()() -> T& { return *pointer; } 36 | auto operator()() const -> const T& { return *pointer; } 37 | 38 | auto data() -> T* { return pointer; } 39 | auto data() const -> const T* { return pointer; } 40 | 41 | auto release() -> T* { 42 | auto result = pointer; 43 | pointer = nullptr; 44 | return result; 45 | } 46 | 47 | auto reset() -> void { 48 | if(pointer) { 49 | if(deleter) { 50 | deleter(pointer); 51 | } else { 52 | delete pointer; 53 | } 54 | pointer = nullptr; 55 | } 56 | } 57 | }; 58 | 59 | template 60 | struct unique_pointer { 61 | using type = T; 62 | T* pointer = nullptr; 63 | function void> deleter; 64 | 65 | unique_pointer(const unique_pointer&) = delete; 66 | auto operator=(const unique_pointer&) -> unique_pointer& = delete; 67 | 68 | unique_pointer(T* pointer = nullptr, const function& deleter = {}) : pointer(pointer), deleter(deleter) {} 69 | ~unique_pointer() { reset(); } 70 | 71 | auto operator=(T* source) -> unique_pointer& { 72 | reset(); 73 | pointer = source; 74 | return *this; 75 | } 76 | 77 | explicit operator bool() const { return pointer; } 78 | 79 | auto operator()() -> T* { return pointer; } 80 | auto operator()() const -> T* { return pointer; } 81 | 82 | auto operator[](uint offset) -> T& { return pointer[offset]; } 83 | auto operator[](uint offset) const -> const T& { return pointer[offset]; } 84 | 85 | auto data() -> T* { return pointer; } 86 | auto data() const -> const T* { return pointer; } 87 | 88 | auto release() -> T* { 89 | auto result = pointer; 90 | pointer = nullptr; 91 | return result; 92 | } 93 | 94 | auto reset() -> void { 95 | if(pointer) { 96 | if(deleter) { 97 | deleter(pointer); 98 | } else { 99 | delete[] pointer; 100 | } 101 | pointer = nullptr; 102 | } 103 | } 104 | }; 105 | 106 | } 107 | -------------------------------------------------------------------------------- /beat/single/apply.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall::Beat::Single { 4 | 5 | inline auto apply(array_view source, array_view beat, maybe manifest = {}, maybe result = {}) -> maybe> { 6 | #define error(text) { if(result) *result = {"error: ", text}; return {}; } 7 | #define warning(text) { if(result) *result = {"warning: ", text}; return target; } 8 | #define success() { if(result) *result = ""; return target; } 9 | if(beat.size() < 19) error("beat size mismatch"); 10 | 11 | vector target; 12 | 13 | uint beatOffset = 0; 14 | auto read = [&]() -> uint8_t { 15 | return beat[beatOffset++]; 16 | }; 17 | 18 | auto decode = [&]() -> uint64_t { 19 | uint64_t data = 0, shift = 1; 20 | while(true) { 21 | uint8_t x = read(); 22 | data += (x & 0x7f) * shift; 23 | if(x & 0x80) break; 24 | shift <<= 7; 25 | data += shift; 26 | } 27 | return data; 28 | }; 29 | 30 | auto write = [&](uint8_t data) { 31 | target.append(data); 32 | }; 33 | 34 | if(read() != 'B') error("beat header invalid"); 35 | if(read() != 'P') error("beat header invalid"); 36 | if(read() != 'S') error("beat header invalid"); 37 | if(read() != '1') error("beat version mismatch"); 38 | if(decode() != source.size()) error("source size mismatch"); 39 | uint targetSize = decode(); 40 | target.reserve(targetSize); 41 | uint metadataSize = decode(); 42 | for(uint n : range(metadataSize)) { 43 | auto data = read(); 44 | if(manifest) manifest->append((char)data); 45 | } 46 | 47 | enum : uint { SourceRead, TargetRead, SourceCopy, TargetCopy }; 48 | 49 | uint sourceRelativeOffset = 0, targetRelativeOffset = 0; 50 | while(beatOffset < beat.size() - 12) { 51 | uint length = decode(); 52 | uint mode = length & 3; 53 | length = (length >> 2) + 1; 54 | 55 | if(mode == SourceRead) { 56 | while(length--) write(source[target.size()]); 57 | } else if(mode == TargetRead) { 58 | while(length--) write(read()); 59 | } else { 60 | int offset = decode(); 61 | offset = offset & 1 ? -(offset >> 1) : (offset >> 1); 62 | if(mode == SourceCopy) { 63 | sourceRelativeOffset += offset; 64 | while(length--) write(source[sourceRelativeOffset++]); 65 | } else { 66 | targetRelativeOffset += offset; 67 | while(length--) write(target[targetRelativeOffset++]); 68 | } 69 | } 70 | } 71 | 72 | uint32_t sourceHash = 0, targetHash = 0, beatHash = 0; 73 | for(uint shift : range(0, 32, 8)) sourceHash |= read() << shift; 74 | for(uint shift : range(0, 32, 8)) targetHash |= read() << shift; 75 | for(uint shift : range(0, 32, 8)) beatHash |= read() << shift; 76 | 77 | if(target.size() != targetSize) warning("target size mismatch"); 78 | if(sourceHash != Hash::CRC32(source).value()) warning("source hash mismatch"); 79 | if(targetHash != Hash::CRC32(target).value()) warning("target hash mismatch"); 80 | if(beatHash != Hash::CRC32({beat.data(), beat.size() - 4}).value()) warning("beat hash mismatch"); 81 | 82 | success(); 83 | #undef error 84 | #undef warning 85 | #undef success 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /cd/efm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //eight-to-fourteen modulation: 4 | //separates each 1-bit by at least two 0-bits and at most ten 0-bits 5 | 6 | namespace nall::CD::EFM { 7 | 8 | //the algorithm to generate this table is unknown 9 | inline auto lookup(uint8_t index) -> uint16_t { 10 | static const uint16_t lookup[256] = { 11 | 0x1220, 0x2100, 0x2420, 0x2220, 0x1100, 0x0110, 0x0420, 0x0900, 12 | 0x1240, 0x2040, 0x2440, 0x2240, 0x1040, 0x0040, 0x0440, 0x0840, 13 | 0x2020, 0x2080, 0x2480, 0x0820, 0x1080, 0x0080, 0x0480, 0x0880, 14 | 0x1210, 0x2010, 0x2410, 0x2210, 0x1010, 0x0210, 0x0410, 0x0810, 15 | 0x0020, 0x2108, 0x0220, 0x0920, 0x1108, 0x0108, 0x1020, 0x0908, 16 | 0x1248, 0x2048, 0x2448, 0x2248, 0x1048, 0x0048, 0x0448, 0x0848, 17 | 0x0100, 0x2088, 0x2488, 0x2110, 0x1088, 0x0088, 0x0488, 0x0888, 18 | 0x1208, 0x2008, 0x2408, 0x2208, 0x1008, 0x0208, 0x0408, 0x0808, 19 | 0x1224, 0x2124, 0x2424, 0x2224, 0x1124, 0x0024, 0x0424, 0x0924, 20 | 0x1244, 0x2044, 0x2444, 0x2244, 0x1044, 0x0044, 0x0444, 0x0844, 21 | 0x2024, 0x2084, 0x2484, 0x0824, 0x1084, 0x0084, 0x0484, 0x0884, 22 | 0x1204, 0x2004, 0x2404, 0x2204, 0x1004, 0x0204, 0x0404, 0x0804, 23 | 0x1222, 0x2122, 0x2422, 0x2222, 0x1122, 0x0022, 0x1024, 0x0922, 24 | 0x1242, 0x2042, 0x2442, 0x2242, 0x1042, 0x0042, 0x0442, 0x0842, 25 | 0x2022, 0x2082, 0x2482, 0x0822, 0x1082, 0x0082, 0x0482, 0x0882, 26 | 0x1202, 0x0248, 0x2402, 0x2202, 0x1002, 0x0202, 0x0402, 0x0802, 27 | 0x1221, 0x2121, 0x2421, 0x2221, 0x1121, 0x0021, 0x0421, 0x0921, 28 | 0x1241, 0x2041, 0x2441, 0x2241, 0x1041, 0x0041, 0x0441, 0x0841, 29 | 0x2021, 0x2081, 0x2481, 0x0821, 0x1081, 0x0081, 0x0481, 0x0881, 30 | 0x1201, 0x2090, 0x2401, 0x2201, 0x1090, 0x0201, 0x0401, 0x0890, 31 | 0x0221, 0x2109, 0x1110, 0x0121, 0x1109, 0x0109, 0x1021, 0x0909, 32 | 0x1249, 0x2049, 0x2449, 0x2249, 0x1049, 0x0049, 0x0449, 0x0849, 33 | 0x0120, 0x2089, 0x2489, 0x0910, 0x1089, 0x0089, 0x0489, 0x0889, 34 | 0x1209, 0x2009, 0x2409, 0x2209, 0x1009, 0x0209, 0x0409, 0x0809, 35 | 0x1120, 0x2111, 0x2490, 0x0224, 0x1111, 0x0111, 0x0490, 0x0911, 36 | 0x0241, 0x2101, 0x0244, 0x0240, 0x1101, 0x0101, 0x0090, 0x0901, 37 | 0x0124, 0x2091, 0x2491, 0x2120, 0x1091, 0x0091, 0x0491, 0x0891, 38 | 0x1211, 0x2011, 0x2411, 0x2211, 0x1011, 0x0211, 0x0411, 0x0811, 39 | 0x1102, 0x0102, 0x2112, 0x0902, 0x1112, 0x0112, 0x1022, 0x0912, 40 | 0x2102, 0x2104, 0x0249, 0x0242, 0x1104, 0x0104, 0x0422, 0x0904, 41 | 0x0122, 0x2092, 0x2492, 0x0222, 0x1092, 0x0092, 0x0492, 0x0892, 42 | 0x1212, 0x2012, 0x2412, 0x2212, 0x1012, 0x0212, 0x0412, 0x0812, 43 | }; 44 | return lookup[index]; 45 | } 46 | 47 | // 48 | 49 | inline auto encode(uint8_t data) -> uint16_t { 50 | return lookup(data); 51 | } 52 | 53 | // 54 | 55 | inline auto decode(uint16_t data) -> maybe { 56 | static uint16_t table[1 << 14]; 57 | static bool once = true; 58 | if(once) { 59 | once = false; 60 | for(uint n : range(1 << 14)) table[n] = 0xffff; 61 | for(uint n : range(1 << 8)) table[lookup(n)] = n; 62 | } 63 | uint16_t result = table[data & 0x3fff]; 64 | if(result == 0xffff) return {}; 65 | return (uint8_t)result; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /primitives/bit-field.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | template struct BitField; 6 | 7 | /* static BitField */ 8 | 9 | template struct BitField { 10 | static_assert(Precision >= 1 && Precision <= 64); 11 | using type = 12 | conditional_t>>>; 17 | enum : uint { shift = Index < 0 ? Precision + Index : Index }; 18 | enum : type { mask = 1ull << shift }; 19 | 20 | BitField(const BitField&) = delete; 21 | 22 | auto& operator=(const BitField& source) { 23 | target = target & ~mask | (bool)source << shift; 24 | return *this; 25 | } 26 | 27 | template BitField(T* source) : target((type&)*source) { 28 | static_assert(sizeof(T) == sizeof(type)); 29 | } 30 | 31 | auto bit() const { 32 | return shift; 33 | } 34 | 35 | operator bool() const { 36 | return target & mask; 37 | } 38 | 39 | auto& operator=(bool source) { 40 | target = target & ~mask | source << shift; 41 | return *this; 42 | } 43 | 44 | auto& operator&=(bool source) { 45 | target = target & (~mask | source << shift); 46 | return *this; 47 | } 48 | 49 | auto& operator^=(bool source) { 50 | target = target ^ source << shift; 51 | return *this; 52 | } 53 | 54 | auto& operator|=(bool source) { 55 | target = target | source << shift; 56 | return *this; 57 | } 58 | 59 | private: 60 | type& target; 61 | }; 62 | 63 | /* dynamic BitField */ 64 | 65 | template struct BitField { 66 | static_assert(Precision >= 1 && Precision <= 64); 67 | using type = 68 | conditional_t>>>; 73 | 74 | BitField(const BitField&) = delete; 75 | 76 | auto& operator=(const BitField& source) { 77 | target = target & ~mask | (bool)source << shift; 78 | return *this; 79 | } 80 | 81 | template BitField(T* source, int index) : target((type&)*source) { 82 | static_assert(sizeof(T) == sizeof(type)); 83 | if(index < 0) index = Precision + index; 84 | mask = 1ull << index; 85 | shift = index; 86 | } 87 | 88 | auto bit() const { 89 | return shift; 90 | } 91 | 92 | operator bool() const { 93 | return target & mask; 94 | } 95 | 96 | auto& operator=(bool source) { 97 | target = target & ~mask | source << shift; 98 | return *this; 99 | } 100 | 101 | auto& operator&=(bool source) { 102 | target = target & (~mask | source << shift); 103 | return *this; 104 | } 105 | 106 | auto& operator^=(bool source) { 107 | target = target ^ source << shift; 108 | return *this; 109 | } 110 | 111 | auto& operator|=(bool source) { 112 | target = target | source << shift; 113 | return *this; 114 | } 115 | 116 | private: 117 | type& target; 118 | type mask; 119 | uint shift; 120 | }; 121 | 122 | } 123 | -------------------------------------------------------------------------------- /queue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //simple circular ring buffer 4 | 5 | #include 6 | #include 7 | 8 | namespace nall { 9 | 10 | template 11 | struct queue { 12 | queue() = default; 13 | queue(const queue& source) { operator=(source); } 14 | queue(queue&& source) { operator=(move(source)); } 15 | ~queue() { reset(); } 16 | 17 | auto operator=(const queue& source) -> queue& { 18 | if(this == &source) return *this; 19 | delete[] _data; 20 | _data = new T[source._capacity]; 21 | _capacity = source._capacity; 22 | _size = source._size; 23 | _read = source._read; 24 | _write = source._write; 25 | for(uint n : range(_capacity)) _data[n] = source._data[n]; 26 | return *this; 27 | } 28 | 29 | auto operator=(queue&& source) -> queue& { 30 | if(this == &source) return *this; 31 | _data = source._data; 32 | _capacity = source._capacity; 33 | _size = source._size; 34 | _read = source._read; 35 | _write = source._write; 36 | source._data = nullptr; 37 | source.reset(); 38 | return *this; 39 | } 40 | 41 | template auto capacity() const -> uint { return _capacity * sizeof(T) / sizeof(U); } 42 | template auto size() const -> uint { return _size * sizeof(T) / sizeof(U); } 43 | auto empty() const -> bool { return _size == 0; } 44 | auto pending() const -> bool { return _size > 0; } 45 | auto full() const -> bool { return _size >= (int)_capacity; } 46 | auto underflow() const -> bool { return _size < 0; } 47 | auto overflow() const -> bool { return _size > (int)_capacity; } 48 | 49 | auto data() -> T* { return _data; } 50 | auto data() const -> const T* { return _data; } 51 | 52 | auto reset() { 53 | delete[] _data; 54 | _data = nullptr; 55 | _capacity = 0; 56 | _size = 0; 57 | _read = 0; 58 | _write = 0; 59 | } 60 | 61 | auto resize(uint capacity, const T& value = {}) -> void { 62 | delete[] _data; 63 | _data = new T[capacity]; 64 | _capacity = capacity; 65 | _size = 0; 66 | _read = 0; 67 | _write = 0; 68 | for(uint n : range(_capacity)) _data[n] = value; 69 | } 70 | 71 | auto flush() -> void { 72 | _size = 0; 73 | _read = 0; 74 | _write = 0; 75 | } 76 | 77 | auto fill(const T& value = {}) -> void { 78 | _size = 0; 79 | _read = 0; 80 | _write = 0; 81 | for(uint n : range(_capacity)) _data[n] = value; 82 | } 83 | 84 | auto peek(uint index) const -> T { 85 | return _data[(_read + index) % _size]; 86 | } 87 | 88 | auto read() -> T { 89 | T value = _data[_read++]; 90 | if(_read >= _capacity) _read = 0; 91 | _size--; 92 | return value; 93 | } 94 | 95 | auto write(const T& value) -> void { 96 | _data[_write++] = value; 97 | if(_write >= _capacity) _write = 0; 98 | _size++; 99 | } 100 | 101 | auto serialize(serializer& s) -> void { 102 | s.array(_data, _capacity); 103 | s.integer(_capacity); 104 | s.integer(_size); 105 | s.integer(_read); 106 | s.integer(_write); 107 | } 108 | 109 | private: 110 | T* _data = nullptr; 111 | uint _capacity = 0; 112 | int _size = 0; 113 | uint _read = 0; 114 | uint _write = 0; 115 | }; 116 | 117 | } 118 | -------------------------------------------------------------------------------- /function.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nall { 6 | 7 | template struct function; 8 | 9 | template struct function R> { 10 | using cast = auto (*)(P...) -> R; 11 | 12 | //value = true if auto L::operator()(P...) -> R exists 13 | template struct is_compatible { 14 | template static auto exists(T*) -> const typename is_same().operator()(declval

()...))>::type; 15 | template static auto exists(...) -> const false_type; 16 | static constexpr bool value = decltype(exists(0))::value; 17 | }; 18 | 19 | function() {} 20 | function(const function& source) { operator=(source); } 21 | function(auto (*function)(P...) -> R) { callback = new global(function); } 22 | template function(auto (C::*function)(P...) -> R, C* object) { callback = new member(function, object); } 23 | template function(auto (C::*function)(P...) const -> R, C* object) { callback = new member((auto (C::*)(P...) -> R)function, object); } 24 | template::value>> function(const L& object) { callback = new lambda(object); } 25 | explicit function(void* function) { if(function) callback = new global((auto (*)(P...) -> R)function); } 26 | ~function() { if(callback) delete callback; } 27 | 28 | explicit operator bool() const { return callback; } 29 | auto operator()(P... p) const -> R { return (*callback)(forward

(p)...); } 30 | auto reset() -> void { if(callback) { delete callback; callback = nullptr; } } 31 | 32 | auto operator=(const function& source) -> function& { 33 | if(this != &source) { 34 | if(callback) { delete callback; callback = nullptr; } 35 | if(source.callback) callback = source.callback->copy(); 36 | } 37 | return *this; 38 | } 39 | 40 | auto operator=(void* source) -> function& { 41 | if(callback) { delete callback; callback = nullptr; } 42 | callback = new global((auto (*)(P...) -> R)source); 43 | return *this; 44 | } 45 | 46 | private: 47 | struct container { 48 | virtual auto operator()(P... p) const -> R = 0; 49 | virtual auto copy() const -> container* = 0; 50 | virtual ~container() = default; 51 | }; 52 | 53 | container* callback = nullptr; 54 | 55 | struct global : container { 56 | auto (*function)(P...) -> R; 57 | auto operator()(P... p) const -> R { return function(forward

(p)...); } 58 | auto copy() const -> container* { return new global(function); } 59 | global(auto (*function)(P...) -> R) : function(function) {} 60 | }; 61 | 62 | template struct member : container { 63 | auto (C::*function)(P...) -> R; 64 | C* object; 65 | auto operator()(P... p) const -> R { return (object->*function)(forward

(p)...); } 66 | auto copy() const -> container* { return new member(function, object); } 67 | member(auto (C::*function)(P...) -> R, C* object) : function(function), object(object) {} 68 | }; 69 | 70 | template struct lambda : container { 71 | mutable L object; 72 | auto operator()(P... p) const -> R { return object(forward

(p)...); } 73 | auto copy() const -> container* { return new lambda(object); } 74 | lambda(const L& object) : object(object) {} 75 | }; 76 | }; 77 | 78 | } 79 | -------------------------------------------------------------------------------- /image/load.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline auto image::loadBMP(const string& filename) -> bool { 6 | if(!file::exists(filename)) return false; 7 | auto buffer = file::read(filename); 8 | return loadBMP(buffer.data(), buffer.size()); 9 | } 10 | 11 | inline auto image::loadBMP(const uint8_t* bmpData, uint bmpSize) -> bool { 12 | Decode::BMP source; 13 | if(!source.load(bmpData, bmpSize)) return false; 14 | 15 | allocate(source.width(), source.height()); 16 | const uint32_t* sp = source.data(); 17 | uint8_t* dp = _data; 18 | 19 | for(uint y = 0; y < _height; y++) { 20 | for(uint x = 0; x < _width; x++) { 21 | uint32_t color = *sp++; 22 | uint64_t a = normalize((uint8_t)(color >> 24), 8, _alpha.depth()); 23 | uint64_t r = normalize((uint8_t)(color >> 16), 8, _red.depth()); 24 | uint64_t g = normalize((uint8_t)(color >> 8), 8, _green.depth()); 25 | uint64_t b = normalize((uint8_t)(color >> 0), 8, _blue.depth()); 26 | write(dp, (a << _alpha.shift()) | (r << _red.shift()) | (g << _green.shift()) | (b << _blue.shift())); 27 | dp += stride(); 28 | } 29 | } 30 | 31 | return true; 32 | } 33 | 34 | inline auto image::loadPNG(const string& filename) -> bool { 35 | if(!file::exists(filename)) return false; 36 | auto buffer = file::read(filename); 37 | return loadPNG(buffer.data(), buffer.size()); 38 | } 39 | 40 | inline auto image::loadPNG(const uint8_t* pngData, uint pngSize) -> bool { 41 | Decode::PNG source; 42 | if(!source.load(pngData, pngSize)) return false; 43 | 44 | allocate(source.info.width, source.info.height); 45 | const uint8_t* sp = source.data; 46 | uint8_t* dp = _data; 47 | 48 | auto decode = [&]() -> uint64_t { 49 | uint64_t p, r, g, b, a; 50 | 51 | switch(source.info.colorType) { 52 | case 0: //L 53 | r = g = b = source.readbits(sp); 54 | a = (1 << source.info.bitDepth) - 1; 55 | break; 56 | case 2: //R,G,B 57 | r = source.readbits(sp); 58 | g = source.readbits(sp); 59 | b = source.readbits(sp); 60 | a = (1 << source.info.bitDepth) - 1; 61 | break; 62 | case 3: //P 63 | p = source.readbits(sp); 64 | r = source.info.palette[p][0]; 65 | g = source.info.palette[p][1]; 66 | b = source.info.palette[p][2]; 67 | a = (1 << source.info.bitDepth) - 1; 68 | break; 69 | case 4: //L,A 70 | r = g = b = source.readbits(sp); 71 | a = source.readbits(sp); 72 | break; 73 | case 6: //R,G,B,A 74 | r = source.readbits(sp); 75 | g = source.readbits(sp); 76 | b = source.readbits(sp); 77 | a = source.readbits(sp); 78 | break; 79 | } 80 | 81 | a = normalize(a, source.info.bitDepth, _alpha.depth()); 82 | r = normalize(r, source.info.bitDepth, _red.depth()); 83 | g = normalize(g, source.info.bitDepth, _green.depth()); 84 | b = normalize(b, source.info.bitDepth, _blue.depth()); 85 | 86 | return (a << _alpha.shift()) | (r << _red.shift()) | (g << _green.shift()) | (b << _blue.shift()); 87 | }; 88 | 89 | for(uint y = 0; y < _height; y++) { 90 | for(uint x = 0; x < _width; x++) { 91 | write(dp, decode()); 92 | dp += stride(); 93 | } 94 | } 95 | 96 | return true; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /image/fill.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nall { 4 | 5 | inline auto image::fill(uint64_t color) -> void { 6 | for(uint y = 0; y < _height; y++) { 7 | uint8_t* dp = _data + pitch() * y; 8 | for(uint x = 0; x < _width; x++) { 9 | write(dp, color); 10 | dp += stride(); 11 | } 12 | } 13 | } 14 | 15 | inline auto image::gradient(uint64_t a, uint64_t b, uint64_t c, uint64_t d) -> void { 16 | for(uint y = 0; y < _height; y++) { 17 | uint8_t* dp = _data + pitch() * y; 18 | double muY = (double)y / (double)_height; 19 | for(uint x = 0; x < _width; x++) { 20 | double muX = (double)x / (double)_width; 21 | write(dp, interpolate4f(a, b, c, d, muX, muY)); 22 | dp += stride(); 23 | } 24 | } 25 | } 26 | 27 | inline auto image::gradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY, function callback) -> void { 28 | for(int y = 0; y < _height; y++) { 29 | uint8_t* dp = _data + pitch() * y; 30 | double py = max(-radiusY, min(+radiusY, y - centerY)) * 1.0 / radiusY; 31 | for(int x = 0; x < _width; x++) { 32 | double px = max(-radiusX, min(+radiusX, x - centerX)) * 1.0 / radiusX; 33 | double mu = max(0.0, min(1.0, callback(px, py))); 34 | if(mu != mu) mu = 1.0; //NaN 35 | write(dp, interpolate4f(a, b, mu)); 36 | dp += stride(); 37 | } 38 | } 39 | } 40 | 41 | inline auto image::crossGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void { 42 | return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { 43 | x = fabs(x), y = fabs(y); 44 | return min(x, y) * min(x, y); 45 | }); 46 | } 47 | 48 | inline auto image::diamondGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void { 49 | return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { 50 | return fabs(x) + fabs(y); 51 | }); 52 | } 53 | 54 | inline auto image::horizontalGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void { 55 | return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { 56 | return fabs(x); 57 | }); 58 | } 59 | 60 | inline auto image::radialGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void { 61 | return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { 62 | return sqrt(x * x + y * y); 63 | }); 64 | } 65 | 66 | inline auto image::sphericalGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void { 67 | return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { 68 | return x * x + y * y; 69 | }); 70 | } 71 | 72 | inline auto image::squareGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void { 73 | return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { 74 | return max(fabs(x), fabs(y)); 75 | }); 76 | } 77 | 78 | inline auto image::verticalGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void { 79 | return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { 80 | return fabs(y); 81 | }); 82 | } 83 | 84 | } 85 | --------------------------------------------------------------------------------