#!/usr/bin/env dub
/+ dub.sdl:
name "autological_sqlite_header_probe"
targetPath "build"
dflags "-preview=in" "-preview=dip1000"
buildType "checked" {
buildOptions "optimize" "inline" "debugInfo"
}
+/
/**
* The 100-byte header that lets a database be an executable.
*
* SQLite reserves the first 100 bytes of every database file for a fixed-layout
* header, and two of its fields are what make the SELF format possible at all:
*
* - **`application_id`**, a 4-byte big-endian integer at **offset 68**. SQLite
* itself never interprets it; the documentation's stated purpose is to let
* `file(1)`-style tools identify *which application's* database this is. A
* `binfmt_misc` registration with `offset=68` and a 4-byte magic therefore
* dispatches on a field the storage engine has promised not to touch.
* - **`page_size`** at offset 16, big-endian, which decides whether segment
* BLOBs can ever be page-aligned — the crux of the lost-`mmap` problem.
*
* This program decodes the header of whatever files are passed on the command
* line, and — with no arguments — of a synthesized SELF header plus the local
* SQLite databases it can find, so it is useful with or without a corpus.
*
* The `Reserved space at end of each page` field (offset 20) is decoded too,
* because it is the one the "segments in SQLite's reserved region" repair
* candidate would have to use, and seeing it default to `0` makes the size of
* that proposal concrete.
*
* Companions:
* docs/research/autological-artifacts/self-selfdb/index.md
* docs/research/autological-artifacts/sqlite-application-file-format.md
* docs/research/autological-artifacts/binfmt-misc.md
*
* Run with: `dub run --single sqlite-header-probe.d [FILE...]`
*
* Portability: pure `std`. Files that are not SQLite databases are reported as
* such rather than treated as an error, so the program always exits 0.
*/
module (module) autological_sqlite_header_probeThe 100-byte header that lets a database be an executable.
SQLite reserves the first 100 bytes of every database file for a fixed-layout
header, and two of its fields are what make the SELF format possible at all:
application_id, a 4-byte big-endian integer at offset 68. SQLite
itself never interprets it; the documentation's stated purpose is to let
file(1)-style tools identify which application's database this is. A
binfmt_misc registration with offset=68 and a 4-byte magic therefore
dispatches on a field the storage engine has promised not to touch.
page_size at offset 16, big-endian, which decides whether segment
BLOBs can ever be page-aligned — the crux of the lost-mmap problem.
This program decodes the header of whatever files are passed on the command
line, and — with no arguments — of a synthesized SELF header plus the local
SQLite databases it can find, so it is useful with or without a corpus.
The Reserved space at end of each page field (offset 20) is decoded too,
because it is the one the "segments in SQLite's reserved region" repair
candidate would have to use, and seeing it default to 0 makes the size of
that proposal concrete.
Companions
docs/research/autological-artifacts/self-selfdb/index.md
docs/research/autological-artifacts/sqlite-application-file-format.md
docs/research/autological-artifacts/binfmt-misc.md
Run with: dub run --single sqlite-header-probe.d [FILE...]
Portability
pure std. Files that are not SQLite databases are reported as
such rather than treated as an error, so the program always exits 0.
autological_sqlite_header_probe;
import (package) stdstd.(module) std.algorithmThis package implements generic algorithms oriented towards the processing of
sequences. Sequences processed by these functions define range-based
interfaces. See also Reference on ranges and
tutorial on ranges.
Algorithms are categorized into the following submodules:
Submodule Functions
| Searching |
all
any
balancedParens
boyerMooreFinder
canFind
commonPrefix
count
countUntil
endsWith
find
findAdjacent
findAmong
findSkip
findSplit
findSplitAfter
findSplitBefore
minCount
maxCount
minElement
maxElement
minIndex
maxIndex
minPos
maxPos
skipOver
startsWith
until
|
| Comparison |
among
castSwitch
clamp
cmp
either
equal
isPermutation
isSameLength
levenshteinDistance
levenshteinDistanceAndPath
max
min
mismatch
predSwitch
|
| Iteration |
cache
cacheBidirectional
chunkBy
cumulativeFold
each
filter
filterBidirectional
fold
group
joiner
map
mean
permutations
reduce
splitWhen
splitter
substitute
sum
uniq
|
| Sorting |
completeSort
isPartitioned
isSorted
isStrictlyMonotonic
ordered
strictlyOrdered
makeIndex
merge
multiSort
nextEvenPermutation
nextPermutation
nthPermutation
partialSort
partition
partition3
schwartzSort
sort
topN
topNCopy
topNIndex
|
| Set operations (setops) |
cartesianProduct
largestPartialIntersection
largestPartialIntersectionWeighted
multiwayMerge
multiwayUnion
setDifference
setIntersection
setSymmetricDifference
|
| Mutation |
bringToFront
copy
fill
initializeAll
move
moveAll
moveSome
moveEmplace
moveEmplaceAll
moveEmplaceSome
remove
reverse
strip
stripLeft
stripRight
swap
swapRanges
uninitializedFill
|
Many functions in this package are parameterized with a predicate.
The predicate may be any suitable callable type
(a function, a delegate, a functor, or a lambda), or a
compile-time string. The string may consist of any legal D
expression that uses the symbol a (for unary functions) or the
symbols a and b (for binary functions). These names will NOT
interfere with other homonym symbols in user code because they are
evaluated in a different context. The default for all binary
comparison predicates is "a == b" for unordered operations and
"a < b" for ordered operations.
Example
int[] a = ...;
static bool greater(int a, int b)
{
return a > b;
}
sort!greater(a); // predicate as alias
sort!((a, b) => a > b)(a); // predicate as a lambda.
sort!"a > b"(a); // predicate as string
// (no ambiguity with array name)
sort(a); // no predicate, "a < b" is implicit
Source
std/algorithm/package.d
algorithm : (alias template) autological_sqlite_header_probe.filter = std.algorithm.iteration.filter(alias predicate) if (is(typeof(unaryFun!predicate)))``filter!(predicate)(range) returns a new range containing only elements x in range for
which predicate(x) returns true.
The predicate is passed to unaryFun, and can be either a string, or
any callable that can be executed via pred(element).
filter, (alias template) autological_sqlite_header_probe.map = std.algorithm.iteration.map(fun...) if (fun.length >= 1)Implements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
map;
import (package) stdstd.(module) std.arrayFunctions and types that manipulate built-in arrays and associative arrays.
This module provides all kinds of functions to create, manipulate or convert arrays:
Function Name Description
| array |
Returns a copy of the input in a newly allocated dynamic array.
|
| appender |
Returns a new Appender or RefAppender initialized with a given array.
|
| assocArray |
Returns a newly allocated associative array from a range/ranges of keys and values.
|
| byPair |
Construct a range iterating over an associative array by key/value tuples.
|
| insertInPlace |
Inserts into an existing array at a given position.
|
| join |
Concatenates a range of ranges into one array.
|
| minimallyInitializedArray |
Returns a new array of type T.
|
| replace |
Returns a new array with all occurrences of a certain subrange replaced.
|
| replaceFirst |
Returns a new array with the first occurrence of a certain subrange replaced.
|
| replaceInPlace |
Replaces all occurrences of a certain subrange and puts the result into a given array.
|
| replaceInto |
Replaces all occurrences of a certain subrange and puts the result into an output range.
|
| replaceLast |
Returns a new array with the last occurrence of a certain subrange replaced.
|
| replaceSlice |
Returns a new array with a given slice replaced.
|
| replicate |
Creates a new array out of several copies of an input array or range.
|
| sameHead |
Checks if the initial segments of two arrays refer to the same
place in memory.
|
| sameTail |
Checks if the final segments of two arrays refer to the same place
in memory.
|
| split |
Eagerly split a range or string into an array.
|
| staticArray |
Creates a new static array from given data.
|
| uninitializedArray |
Returns a new array of type T without initializing its elements.
|
Source
std/array.d
array : (alias template) autological_sqlite_header_probe.array = std.array.array(Range)(Range r) if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)Allocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array;
import (package) stdstd.(module) std.convA one-stop shop for converting values from one type to another.
Category Functions Generic asOriginalType castFrom parse to toChars bitCast Strings text wtext dtext writeText writeWText writeDText hexString Numeric octal roundTo signed unsigned Exceptions ConvException ConvOverflowException
Source
std/conv.d
conv : (alias template) autological_sqlite_header_probe.text = std.conv.text(T...)(T args) if (T.length > 0)Convenience functions for converting one or more arguments
of any type into text (the three character widths).
text;
import (package) stdstd.(module) std.fileUtilities for manipulating files and scanning directories. Functions
in this module handle files as a unit, e.g., read or write one file
at a time. For opening files and manipulating them via handles refer
to module std.stdio.
Category Functions General exists isDir isFile isSymlink rename thisExePath Directories chdir dirEntries getcwd mkdir mkdirRecurse rmdir rmdirRecurse tempDir Files append copy read readText remove slurp write Symlinks symlink readLink Attributes attrIsDir attrIsFile attrIsSymlink getAttributes getLinkAttributes getSize setAttributes Timestamp getTimes getTimesWin setTimes timeLastModified timeLastAccessed timeStatusChanged Other DirEntry FileException PreserveAttributes SpanMode getAvailableDiskSpace
Source
std/file.d
file : (alias template) autological_sqlite_header_probe.exists = std.file.exists(R)(R name) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Determine whether the given file (or directory) exists.
exists, (alias template) autological_sqlite_header_probe.isFile = std.file.isFile(R)(R name) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Returns whether the given file (or directory) is a file.
On Windows, if a file is not a directory, then it's a file. So,
either isFile or isDir will return true for any given file.
On POSIX systems, if isFile is true, that indicates that the file
is a regular file (e.g. not a block not device). So, on POSIX systems, it's
possible for both isFile and isDir to be false for a
particular file (in which case, it's a special file). You can use
getAttributes to get the attributes to figure out what type of special
it is, or you can use DirEntry to get at its statBuf, which is the
result from stat. In either case, see the man page for stat for
more information.
isFile, (alias template) autological_sqlite_header_probe.read = std.file.read(R)(R name, size_t upTo = size_t.max) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Read entire contents of file name and returns it as an untyped
array. If the file size is larger than upTo, only upTo
bytes are read.
read;
import (package) stdstd.(module) std.stdioCategory Symbols File handles _popen File isFileHandle openNetwork stderr stdin stdout Reading chunks lines readf readfln readln Writing toFile write writef writefln writeln Misc KeepTerminator LockType StdioException
Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio
is publically imported when importing std.stdio.
There are three layers of I/O:
The lowest layer is the operating system layer. The two main schemes are Windows and Posix.
C's stdio.h which unifies the two operating system schemes.
std.stdio, this module, unifies the various stdio.h implementations into
a high level package for D programs.
Source
std/stdio.d
stdio : (alias template) autological_sqlite_header_probe.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))Equivalent to writef(fmt, args, '\n').
writefln, (alias template) autological_sqlite_header_probe.writeln = std.stdio.writeln(T...)(T args)Equivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
import (package) stdstd.(module) std.stringString handling functions.
Category Functions Searching column indexOf indexOfAny indexOfNeither lastIndexOf lastIndexOfAny lastIndexOfNeither Comparison isNumeric Mutation capitalize Pruning and Filling center chomp chompPrefix chop detabber detab entab entabber leftJustify outdent rightJustify strip stripLeft stripRight wrap Substitution abbrev soundex soundexer succ tr translate Miscellaneous assumeUTF fromStringz lineSplitter representation splitLines toStringz Objects of types string, wstring, and dstring are value types and cannot be mutated element-by-element. For using mutation during building strings, use char[], wchar[], or dchar[]. The xxxstring types are preferable because they don't exhibit undesired aliasing, thus making code more robust.
The following functions are publicly imported:
Module Functions Publicly imported functions std.algorithm cmp, std,algorithm,comparison count, std,algorithm,searching endsWith, std,algorithm,searching startsWith, std,algorithm,searching std.array join, std,array replace, std,array replaceInPlace, std,array split, std,array empty, std,array std.format format, std,format sformat, std,format std.uni icmp, std,uni toLower, std,uni toLowerInPlace, std,uni toUpper, std,uni toUpperInPlace, std,uni There is a rich set of functions for string handling defined in other modules. Functions related to Unicode and ASCII are found in std.uni and std.ascii, respectively. Other functions that have a wider generality than just strings can be found in std.algorithm and std.range.
Source
std/string.d
string : (alias template) autological_sqlite_header_probe.representation = std.string.representation(Char)(Char[] s) if (isSomeChar!Char)Returns the representation of a string, which has the same type
as the string except the character type is replaced by ubyte,
ushort, or uint depending on the character width.
representation;
/// The header magic every SQLite 3 database opens with, `NUL` included.
enum (alias) object.string = stringstring (constant) string autological_sqlite_header_probe.sqliteMagic = "SQLite format 3\0"The header magic every SQLite 3 database opens with, NUL included.
sqliteMagic = "SQLite format 3\0";
/++
The subset of the 100-byte header this catalog cares about.
Offsets are from the SQLite file-format documentation; every multi-byte integer
in the header is **big-endian**, which is worth stating because the rest of the
formats in this tree (ZIP, ELF, PE) are little-endian, and a polyglot has to
keep both straight.
+/
struct (struct) autological_sqlite_header_probe.SqliteHeaderThe subset of the 100-byte header this catalog cares about.
Offsets are from the SQLite file-format documentation; every multi-byte integer
in the header is big-endian, which is worth stating because the rest of the
formats in this tree (ZIP, ELF, PE) are little-endian, and a polyglot has to
keep both straight.
SqliteHeader
{
ushort (field) ushort autological_sqlite_header_probe.SqliteHeader.pageSizeRawpageSizeRaw; // offset 16; 1 means 65536
ubyte (field) ubyte autological_sqlite_header_probe.SqliteHeader.writeVersionwriteVersion; // offset 18; 1 = legacy, 2 = WAL
ubyte (field) ubyte autological_sqlite_header_probe.SqliteHeader.readVersionreadVersion; // offset 19
ubyte (field) ubyte autological_sqlite_header_probe.SqliteHeader.reservedPerPagereservedPerPage; // offset 20
uint (field) uint autological_sqlite_header_probe.SqliteHeader.changeCounterchangeCounter; // offset 24
uint (field) uint autological_sqlite_header_probe.SqliteHeader.sizeInPagessizeInPages; // offset 28
uint (field) uint autological_sqlite_header_probe.SqliteHeader.schemaCookieschemaCookie; // offset 40
uint (field) uint autological_sqlite_header_probe.SqliteHeader.textEncodingtextEncoding; // offset 56; 1 = UTF-8, 2 = UTF-16le, 3 = UTF-16be
uint (field) uint autological_sqlite_header_probe.SqliteHeader.userVersionuserVersion; // offset 60
uint (field) uint autological_sqlite_header_probe.SqliteHeader.applicationIdapplicationId; // offset 68
uint (field) uint autological_sqlite_header_probe.SqliteHeader.sqliteVersionNumbersqliteVersionNumber; // offset 96
/// The real page size, resolving the documented `1 == 65536` escape.
uint uint autological_sqlite_header_probe.SqliteHeader.pageSize() const pure nothrow @nogc @safeThe real page size, resolving the documented 1 == 65536 escape.
pageSize() const @safe pure nothrow @nogc
=> (field) ushort autological_sqlite_header_probe.SqliteHeader.pageSizeRawpageSizeRaw == 1 ? 65_536 : (field) ushort autological_sqlite_header_probe.SqliteHeader.pageSizeRawpageSizeRaw;
/// `application_id` rendered as the four ASCII bytes tools usually put there.
(alias) object.string = stringstring string autological_sqlite_header_probe.SqliteHeader.applicationTag() const pure @safeapplication_id rendered as the four ASCII bytes tools usually put there.
applicationTag() const @safe pure
{
char[4] (local variable) char[4] tagtag;
foreach ((local variable) int ii; 0 .. 4)
{
const (local variable) const(ubyte) bb = cast(ubyte)((field) uint autological_sqlite_header_probe.SqliteHeader.applicationIdapplicationId >> (8 * (3 - (local variable) int ii)));
(local variable) char[4] tagtag[(local variable) int ii] = ((local variable) const(ubyte) bb >= 0x20 && (local variable) const(ubyte) bb < 0x7f) ? cast(char) (local variable) const(ubyte) bb : '.';
}
return (local variable) char[4] tagtag.string object.idup!char(char[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
}
}
/// Reads a big-endian `uint` at `offset`.
uint uint autological_sqlite_header_probe.beU32(in ubyte[] b, ulong offset) pure nothrow @nogc @safeReads a big-endian uint at offset.
beU32(in ubyte[] (parameter) const(ubyte[]) bb, (alias) object.size_t = ulongsize_t (parameter) ulong offsetoffset) @safe pure nothrow @nogc
in ((parameter) ulong offsetoffset + 4 <= (parameter) const(ubyte[]) bb.(field) ulong const(ubyte[]).lengthlength)
=> (uint((parameter) const(ubyte[]) bb[(parameter) ulong offsetoffset]) << 24) | (uint((parameter) const(ubyte[]) bb[(parameter) ulong offsetoffset + 1]) << 16)
| (uint((parameter) const(ubyte[]) bb[(parameter) ulong offsetoffset + 2]) << 8) | uint((parameter) const(ubyte[]) bb[(parameter) ulong offsetoffset + 3]);
/// Reads a big-endian `ushort` at `offset`.
ushort ushort autological_sqlite_header_probe.beU16(in ubyte[] b, ulong offset) pure nothrow @nogc @safeReads a big-endian ushort at offset.
beU16(in ubyte[] (parameter) const(ubyte[]) bb, (alias) object.size_t = ulongsize_t (parameter) ulong offsetoffset) @safe pure nothrow @nogc
in ((parameter) ulong offsetoffset + 2 <= (parameter) const(ubyte[]) bb.(field) ulong const(ubyte[]).lengthlength)
=> cast(ushort)((ushort((parameter) const(ubyte[]) bb[(parameter) ulong offsetoffset]) << 8) | (parameter) const(ubyte[]) bb[(parameter) ulong offsetoffset + 1]);
/// True when `b` opens with the SQLite 3 header magic.
bool bool autological_sqlite_header_probe.isSqlite(in ubyte[] b) pure nothrow @nogc @safeTrue when b opens with the SQLite 3 header magic.
isSqlite(in ubyte[] (parameter) const(ubyte[]) bb) @safe pure nothrow @nogc
=> (parameter) const(ubyte[]) bb.(field) ulong const(ubyte[]).lengthlength >= 100 && (parameter) const(ubyte[]) bb[0 .. 16] == (constant) string autological_sqlite_header_probe.sqliteMagic = "SQLite format 3\0"The header magic every SQLite 3 database opens with, NUL included.
sqliteMagic.immutable(ubyte)[] std.string.representation!(immutable(char))(string s) pure nothrow @nogc @safeReturns the representation of a string, which has the same type
as the string except the character type is replaced by ubyte,
ushort, or uint depending on the character width.
Examples
string s = "hello";
static assert(is(typeof(representation(s)) == immutable(ubyte)[]));
assert(representation(s) is cast(immutable(ubyte)[]) s);
assert(representation(s) == [0x68, 0x65, 0x6c, 0x6c, 0x6f]);
representation;
/// Decodes the header fields this catalog reads.
(struct) autological_sqlite_header_probe.SqliteHeaderThe subset of the 100-byte header this catalog cares about.
Offsets are from the SQLite file-format documentation; every multi-byte integer
in the header is big-endian, which is worth stating because the rest of the
formats in this tree (ZIP, ELF, PE) are little-endian, and a polyglot has to
keep both straight.
SqliteHeader autological_sqlite_header_probe.SqliteHeader autological_sqlite_header_probe.decode(in ubyte[] b) pure nothrow @nogc @safeDecodes the header fields this catalog reads.
decode(in ubyte[] (parameter) const(ubyte[]) bb) @safe pure nothrow @nogc
in (bool autological_sqlite_header_probe.isSqlite(in ubyte[] b) pure nothrow @nogc @safeTrue when b opens with the SQLite 3 header magic.
isSqlite((parameter) const(ubyte[]) bb))
{
(struct) autological_sqlite_header_probe.SqliteHeaderThe subset of the 100-byte header this catalog cares about.
Offsets are from the SQLite file-format documentation; every multi-byte integer
in the header is big-endian, which is worth stating because the rest of the
formats in this tree (ZIP, ELF, PE) are little-endian, and a polyglot has to
keep both straight.
SqliteHeader (local variable) autological_sqlite_header_probe.SqliteHeader hh;
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) ushort autological_sqlite_header_probe.SqliteHeader.pageSizeRawpageSizeRaw = ushort autological_sqlite_header_probe.beU16(in ubyte[] b, ulong offset) pure nothrow @nogc @safeReads a big-endian ushort at offset.
beU16((parameter) const(ubyte[]) bb, 16);
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) ubyte autological_sqlite_header_probe.SqliteHeader.writeVersionwriteVersion = (parameter) const(ubyte[]) bb[18];
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) ubyte autological_sqlite_header_probe.SqliteHeader.readVersionreadVersion = (parameter) const(ubyte[]) bb[19];
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) ubyte autological_sqlite_header_probe.SqliteHeader.reservedPerPagereservedPerPage = (parameter) const(ubyte[]) bb[20];
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) uint autological_sqlite_header_probe.SqliteHeader.changeCounterchangeCounter = uint autological_sqlite_header_probe.beU32(in ubyte[] b, ulong offset) pure nothrow @nogc @safeReads a big-endian uint at offset.
beU32((parameter) const(ubyte[]) bb, 24);
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) uint autological_sqlite_header_probe.SqliteHeader.sizeInPagessizeInPages = uint autological_sqlite_header_probe.beU32(in ubyte[] b, ulong offset) pure nothrow @nogc @safeReads a big-endian uint at offset.
beU32((parameter) const(ubyte[]) bb, 28);
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) uint autological_sqlite_header_probe.SqliteHeader.schemaCookieschemaCookie = uint autological_sqlite_header_probe.beU32(in ubyte[] b, ulong offset) pure nothrow @nogc @safeReads a big-endian uint at offset.
beU32((parameter) const(ubyte[]) bb, 40);
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) uint autological_sqlite_header_probe.SqliteHeader.textEncodingtextEncoding = uint autological_sqlite_header_probe.beU32(in ubyte[] b, ulong offset) pure nothrow @nogc @safeReads a big-endian uint at offset.
beU32((parameter) const(ubyte[]) bb, 56);
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) uint autological_sqlite_header_probe.SqliteHeader.userVersionuserVersion = uint autological_sqlite_header_probe.beU32(in ubyte[] b, ulong offset) pure nothrow @nogc @safeReads a big-endian uint at offset.
beU32((parameter) const(ubyte[]) bb, 60);
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) uint autological_sqlite_header_probe.SqliteHeader.applicationIdapplicationId = uint autological_sqlite_header_probe.beU32(in ubyte[] b, ulong offset) pure nothrow @nogc @safeReads a big-endian uint at offset.
beU32((parameter) const(ubyte[]) bb, 68);
(local variable) autological_sqlite_header_probe.SqliteHeader hh.(field) uint autological_sqlite_header_probe.SqliteHeader.sqliteVersionNumbersqliteVersionNumber = uint autological_sqlite_header_probe.beU32(in ubyte[] b, ulong offset) pure nothrow @nogc @safeReads a big-endian uint at offset.
beU32((parameter) const(ubyte[]) bb, 96);
return (local variable) autological_sqlite_header_probe.SqliteHeader hh;
}
/// Renders one decoded header as the catalog wants to read it.
void void autological_sqlite_header_probe.report(string label, in autological_sqlite_header_probe.SqliteHeader h) @safeRenders one decoded header as the catalog wants to read it.
report((alias) object.string = stringstring (parameter) string labellabel, in (struct) autological_sqlite_header_probe.SqliteHeaderThe subset of the 100-byte header this catalog cares about.
Offsets are from the SQLite file-format documentation; every multi-byte integer
in the header is big-endian, which is worth stating because the rest of the
formats in this tree (ZIP, ELF, PE) are little-endian, and a polyglot has to
keep both straight.
SqliteHeader (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh) @safe
{
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln("%s", (parameter) string labellabel);
void std.stdio.writefln!(char, uint, string)(in char[] fmt, uint __param_1, string __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" page size (off 16) %s bytes%s", (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.uint autological_sqlite_header_probe.SqliteHeader.pageSize() const pure nothrow @nogc @safeThe real page size, resolving the documented 1 == 65536 escape.
pageSize,
(parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.uint autological_sqlite_header_probe.SqliteHeader.pageSize() const pure nothrow @nogc @safeThe real page size, resolving the documented 1 == 65536 escape.
pageSize >= 4096 ? " (>= a 4 KiB VM page — alignment is at least possible)"
: " (< a 4 KiB VM page — a page-aligned BLOB cannot fit one VM page)");
void std.stdio.writefln!(char, const(ubyte), const(ubyte), string)(in char[] fmt, const(ubyte) __param_1, const(ubyte) __param_2, string __param_3) @safeEquivalent to writef(fmt, args, '\n').
writefln(" write/read version (18/19) %s / %s%s", (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) ubyte autological_sqlite_header_probe.SqliteHeader.writeVersionwriteVersion, (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) ubyte autological_sqlite_header_probe.SqliteHeader.readVersionreadVersion,
(parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) ubyte autological_sqlite_header_probe.SqliteHeader.writeVersionwriteVersion == 2 ? " (WAL)" : " (rollback journal)");
void std.stdio.writefln!(char, const(ubyte), string)(in char[] fmt, const(ubyte) __param_1, string __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" reserved per page (off 20) %s bytes%s", (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) ubyte autological_sqlite_header_probe.SqliteHeader.reservedPerPagereservedPerPage,
(parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) ubyte autological_sqlite_header_probe.SqliteHeader.reservedPerPagereservedPerPage == 0 ? " (the region a 'segments in reserved space' design would claim)" : "");
void std.stdio.writefln!(char, const(uint))(in char[] fmt, const(uint) __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln(" change counter (off 24) %s", (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) uint autological_sqlite_header_probe.SqliteHeader.changeCounterchangeCounter);
void std.stdio.writefln!(char, const(uint), ulong)(in char[] fmt, const(uint) __param_1, ulong __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" size in pages (off 28) %s => %s bytes of database",
(parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) uint autological_sqlite_header_probe.SqliteHeader.sizeInPagessizeInPages, ulong((parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) uint autological_sqlite_header_probe.SqliteHeader.sizeInPagessizeInPages) * (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.uint autological_sqlite_header_probe.SqliteHeader.pageSize() const pure nothrow @nogc @safeThe real page size, resolving the documented 1 == 65536 escape.
pageSize);
void std.stdio.writefln!(char, const(uint), string)(in char[] fmt, const(uint) __param_1, string __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" text encoding (off 56) %s (%s)", (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) uint autological_sqlite_header_probe.SqliteHeader.textEncodingtextEncoding, string autological_sqlite_header_probe.encodingName(uint e) pure nothrow @nogc @safeMaps the documented text-encoding constants to names.
encodingName((parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) uint autological_sqlite_header_probe.SqliteHeader.textEncodingtextEncoding));
void std.stdio.writefln!(char, const(uint))(in char[] fmt, const(uint) __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln(" user_version (off 60) %s", (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) uint autological_sqlite_header_probe.SqliteHeader.userVersionuserVersion);
void std.stdio.writefln!(char, const(uint), string, string)(in char[] fmt, const(uint) __param_1, string __param_2, string __param_3) @safeEquivalent to writef(fmt, args, '\n').
writefln(" application_id (off 68) 0x%08x '%s'%s", (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) uint autological_sqlite_header_probe.SqliteHeader.applicationIdapplicationId, (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.string autological_sqlite_header_probe.SqliteHeader.applicationTag() const pure @safeapplication_id rendered as the four ASCII bytes tools usually put there.
applicationTag,
(parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) uint autological_sqlite_header_probe.SqliteHeader.applicationIdapplicationId == 0 ? " (unset — no binfmt_misc handle)"
: " <-- the 4 bytes binfmt_misc can match on at offset 68");
void std.stdio.writefln!(char, const(uint))(in char[] fmt, const(uint) __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln(" sqlite_version (off 96) %s", (parameter) const(autological_sqlite_header_probe.SqliteHeader) hh.(field) uint autological_sqlite_header_probe.SqliteHeader.sqliteVersionNumbersqliteVersionNumber);
void std.stdio.writeln!()() @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
}
/// Maps the documented text-encoding constants to names.
(alias) object.string = stringstring string autological_sqlite_header_probe.encodingName(uint e) pure nothrow @nogc @safeMaps the documented text-encoding constants to names.
encodingName(uint (parameter) uint ee) @safe pure nothrow @nogc
{
switch ((parameter) uint ee)
{
case 0:
return "unset";
case 1:
return "UTF-8";
case 2:
return "UTF-16le";
case 3:
return "UTF-16be";
default:
return "invalid";
}
}
/++
Synthesizes the header a SELF-style artifact would carry.
Nothing here is guesswork about SELF's internals: it is the *minimum* a file
needs so that (a) SQLite opens it and (b) a `binfmt_misc` rule keyed on
`offset=68, magic=SELF` selects an interpreter for it.
+/
immutable(ubyte)[] immutable(ubyte)[] autological_sqlite_header_probe.synthesize() pure @safeSynthesizes the header a SELF-style artifact would carry.
Nothing here is guesswork about SELF's internals: it is the minimum a file
needs so that (a) SQLite opens it and (b) a binfmt_misc rule keyed on
offset=68, magic=SELF selects an interpreter for it.
synthesize() @safe pure
{
auto (local variable) ubyte[] hh = new ubyte[100];
(local variable) ubyte[] hh[0 .. 16] = (constant) string autological_sqlite_header_probe.sqliteMagic = "SQLite format 3\0"The header magic every SQLite 3 database opens with, NUL included.
sqliteMagic.immutable(ubyte)[] std.string.representation!(immutable(char))(string s) pure nothrow @nogc @safeReturns the representation of a string, which has the same type
as the string except the character type is replaced by ubyte,
ushort, or uint depending on the character width.
Examples
string s = "hello";
static assert(is(typeof(representation(s)) == immutable(ubyte)[]));
assert(representation(s) is cast(immutable(ubyte)[]) s);
assert(representation(s) == [0x68, 0x65, 0x6c, 0x6c, 0x6f]);
representation;
(local variable) ubyte[] hh[16] = 0x10;
(local variable) ubyte[] hh[17] = 0x00; // page_size = 4096
(local variable) ubyte[] hh[18] = 1; // write version: legacy rollback journal
(local variable) ubyte[] hh[19] = 1; // read version
(local variable) ubyte[] hh[20] = 0; // reserved space per page
(local variable) ubyte[] hh[28] = 0;
(local variable) ubyte[] hh[31] = 4; // size in pages = 4
(local variable) ubyte[] hh[56 + 3] = 1; // text encoding = UTF-8
(local variable) ubyte[] hh[68 .. 72] = "SELF".immutable(ubyte)[] std.string.representation!(immutable(char))(string s) pure nothrow @nogc @safeReturns the representation of a string, which has the same type
as the string except the character type is replaced by ubyte,
ushort, or uint depending on the character width.
Examples
string s = "hello";
static assert(is(typeof(representation(s)) == immutable(ubyte)[]));
assert(representation(s) is cast(immutable(ubyte)[]) s);
assert(representation(s) == [0x68, 0x65, 0x6c, 0x6c, 0x6f]);
representation; // application_id
return (local variable) ubyte[] hh.immutable(ubyte)[] object.idup!ubyte(ubyte[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
}
int int D main(string[] args)main((alias) object.string = stringstring[] (parameter) string[] argsargs)
{
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("SQLite header probe — offset 68 is the byte that makes a database dispatchable.");
void std.stdio.writeln!()() @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
void autological_sqlite_header_probe.report(string label, in autological_sqlite_header_probe.SqliteHeader h) @safeRenders one decoded header as the catalog wants to read it.
report("synthesized SELF-style header (not read from disk)", autological_sqlite_header_probe.SqliteHeader autological_sqlite_header_probe.decode(in ubyte[] b) pure nothrow @nogc @safeDecodes the header fields this catalog reads.
decode(immutable(ubyte)[] autological_sqlite_header_probe.synthesize() pure @safeSynthesizes the header a SELF-style artifact would carry.
Nothing here is guesswork about SELF's internals: it is the minimum a file
needs so that (a) SQLite opens it and (b) a binfmt_misc rule keyed on
offset=68, magic=SELF selects an interpreter for it.
synthesize()));
auto (local variable) string[] candidatescandidates = (parameter) string[] argsargs.(field) ulong string[].lengthlength > 1
? (parameter) string[] argsargs[1 .. $]
: ["/var/lib/dbus/machine-id.sqlite", "test.db"].std.algorithm.iteration.FilterResult!(exists, string[]) std.algorithm.iteration.filter!(exists).filter!(string[])(string[] range) pure nothrow @nogc @safefilter`!(predicate)(`range`)` returns a new `range` containing only elements `x` in range`` for
which predicate(x) returns true.
The predicate is passed to unaryFun, and can be either a string, or
any callable that can be executed via pred(element).
Examples
import std.algorithm.comparison : equal;
import std.math.operations : isClose;
import std.range;
int[] arr = [ 1, 2, 3, 4, 5 ];
// Filter below 3
auto small = filter!(a => a < 3)(arr);
assert(equal(small, [ 1, 2 ]));
// Filter again, but with Uniform Function Call Syntax (UFCS)
auto sum = arr.filter!(a => a < 3);
assert(equal(sum, [ 1, 2 ]));
// In combination with chain() to span multiple ranges
int[] a = [ 3, -2, 400 ];
int[] b = [ 100, -101, 102 ];
auto r = chain(a, b).filter!(a => a > 0);
assert(equal(r, [ 3, 400, 100, 102 ]));
// Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ];
auto r1 = chain(c, a, b).filter!(a => cast(int) a != a);
assert(isClose(r1, [ 2.5 ]));
filter!(template) std.file.exists(R)(R name) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Determine whether the given file (or directory) exists.
exists.string[] std.array.array!(std.algorithm.iteration.FilterResult!(exists, string[]))(std.algorithm.iteration.FilterResult!(exists, string[]) r) nothrow @safeAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array;
if ((local variable) string[] candidatescandidates.(field) ulong string[].lengthlength == 0)
{
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("SKIP: no database files given or found locally — pass paths as arguments");
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln(" to decode real headers (e.g. any *.sqlite / *.db on this machine).");
return 0;
}
foreach ((parameter) string pathpath; (local variable) string[] candidatescandidates)
{
if (!(local variable) string pathpath.bool std.file.exists!string(string name) nothrow @nogc @safeDetermine whether the given file (or directory) exists.
exists || !(local variable) string pathpath.bool std.file.isFile!string(string name) @property @safeReturns whether the given file (or directory) is a file.
On Windows, if a file is not a directory, then it's a file. So,
either isFile or isDir will return true for any given file.
On POSIX systems, if isFile is true, that indicates that the file
is a regular file (e.g. not a block not device). So, on POSIX systems, it's
possible for both isFile and isDir to be false for a
particular file (in which case, it's a special file). You can use
getAttributes to get the attributes to figure out what type of special
it is, or you can use DirEntry to get at its statBuf, which is the
result from stat. In either case, see the man page for stat for
more information.
isFile)
{
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln("%s: not a readable file — skipped", (local variable) string pathpath);
continue;
}
const (local variable) const(ubyte[]) bytesbytes = cast(ubyte[]) void[] std.file.read!string(string name, ulong upTo = 18446744073709551615LU) @safeRead entire contents of file name and returns it as an untyped
array. If the file size is larger than upTo, only upTo
bytes are read.
Examples
import std.utf : byChar;
scope(exit)
{
assert(exists(deleteme));
remove(deleteme);
}
std.file.write(deleteme, "1234"); // deleteme is the name of a temporary file
assert(read(deleteme, 2) == "12");
assert(read(deleteme.byChar) == "1234");
assert((cast(const(ubyte)[])read(deleteme)).length == 4);
read((local variable) string pathpath, 100);
if (!bool autological_sqlite_header_probe.isSqlite(in ubyte[] b) pure nothrow @nogc @safeTrue when b opens with the SQLite 3 header magic.
isSqlite((local variable) const(ubyte[]) bytesbytes))
{
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln("%s: not a SQLite database (first 16 bytes are not the header magic)", (local variable) string pathpath);
void std.stdio.writeln!()() @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
continue;
}
void autological_sqlite_header_probe.report(string label, in autological_sqlite_header_probe.SqliteHeader h) @safeRenders one decoded header as the catalog wants to read it.
report((local variable) string pathpath, autological_sqlite_header_probe.SqliteHeader autological_sqlite_header_probe.decode(in ubyte[] b) pure nothrow @nogc @safeDecodes the header fields this catalog reads.
decode((local variable) const(ubyte[]) bytesbytes));
}
return 0;
}