#!/usr/bin/env dub
/+ dub.sdl:
name "autological_zip_eocd_scan"
targetPath "build"
dflags "-preview=in" "-preview=dip1000"
buildType "checked" {
buildOptions "optimize" "inline" "debugInfo"
}
+/
/**
* Suffix parasitism from first principles: a ZIP archive with arbitrary bytes
* glued to its front, still readable — and readable from the *tail alone*.
*
* This program builds a two-entry, `STORED` (uncompressed) ZIP archive by hand,
* prefixes it with an unrelated payload (here a shell script, standing in for an
* ELF/PE/Mach-O image), and then reads it back the way a conformant ZIP reader
* must: scan backwards from EOF for the End Of Central Directory signature
* `PK\x05\x06`, take the central-directory offset and size out of it, and parse
* only those bytes.
*
* Two properties are demonstrated, and they are the ones the catalog's whole
* argument rests on:
*
* 1. **The prefix is legal.** Nothing in the format says byte 0 is a local file
* header. Every internal pointer is an absolute offset from the start of the
* file, so a reader that finds the footer can find everything else. This is
* exactly why `redbean` can be a PE + ELF + Mach-O image *and* a ZIP.
* 2. **Reading is sub-linear.** The program reports how many bytes it actually
* touched to enumerate the archive versus the file size. A footer-anchored
* index is what makes a ranged/partial read possible at all — the same
* property Parquet, ORC and `eStargz` monetize over HTTP range requests.
*
* The offsets written into the central directory deliberately *include* the
* prefix length. Getting that wrong is the single most common way a hand-built
* polyglot breaks, and it is precisely what `zip -A` ("adjust self-extracting
* archive") exists to repair.
*
* Companions:
* docs/research/autological-artifacts/zip-parasitism.md
* docs/research/autological-artifacts/footer-indexed-formats.md
* docs/research/autological-artifacts/cosmopolitan-ape/index.md
*
* Run with: `dub run --single zip-eocd-scan.d`
*
* Portability: pure `std`, no syscalls beyond a temp file. If a system `unzip`
* is on `PATH` the program additionally asks it to list the polyglot, proving an
* independent implementation agrees; if not, it prints a `SKIP:` line for that
* step and still exits 0.
*/
module (module) autological_zip_eocd_scanSuffix parasitism from first principles: a ZIP archive with arbitrary bytes
glued to its front, still readable — and readable from the tail alone.
This program builds a two-entry, STORED (uncompressed) ZIP archive by hand,
prefixes it with an unrelated payload (here a shell script, standing in for an
ELF/PE/Mach-O image), and then reads it back the way a conformant ZIP reader
must: scan backwards from EOF for the End Of Central Directory signature
PK\x05\x06, take the central-directory offset and size out of it, and parse
only those bytes.
Two properties are demonstrated, and they are the ones the catalog's whole
argument rests on:
The prefix is legal. Nothing in the format says byte 0 is a local file
header. Every internal pointer is an absolute offset from the start of the
file, so a reader that finds the footer can find everything else. This is
exactly why redbean can be a PE + ELF + Mach-O image and a ZIP.
Reading is sub-linear. The program reports how many bytes it actually
touched to enumerate the archive versus the file size. A footer-anchored
index is what makes a ranged/partial read possible at all — the same
property Parquet, ORC and eStargz monetize over HTTP range requests.
The offsets written into the central directory deliberately include the
prefix length. Getting that wrong is the single most common way a hand-built
polyglot breaks, and it is precisely what zip -A ("adjust self-extracting
archive") exists to repair.
Companions
docs/research/autological-artifacts/zip-parasitism.md
docs/research/autological-artifacts/footer-indexed-formats.md
docs/research/autological-artifacts/cosmopolitan-ape/index.md
Run with: dub run --single zip-eocd-scan.d
Portability
pure std, no syscalls beyond a temp file. If a system unzip
is on PATH the program additionally asks it to list the polyglot, proving an
independent implementation agrees; if not, it prints a SKIP: line for that
step and still exits 0.
autological_zip_eocd_scan;
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_zip_eocd_scan.appender = std.array.appender(A)() if (isDynamicArray!A)Convenience function that returns an Appender instance,
optionally initialized with array.
appender;
import (package) stdstd.(module) std.bitmanipBit-level manipulation facilities.
Category Functions Bit constructs BitArray bitfields bitsSet Endianness conversion bigEndianToNative littleEndianToNative nativeToBigEndian nativeToLittleEndian swapEndian Integral ranges append peek read write Floating-Point manipulation DoubleRep FloatRep Tagging taggedClassRef taggedPointer
Source
std/bitmanip.d
bitmanip : (alias template) autological_zip_eocd_scan.littleEndianToNative = std.bitmanip.littleEndianToNative(T, ulong n)(ubyte[n] val) if (canSwapEndianness!T && (n == T.sizeof))Converts the given value from little endian to the native endianness and
returns it. The value is given as a ubyte[n] where n is the size
of the target type. You must give the target type as a template argument,
because there are multiple types with the same size and so the type of the
argument is not enough to determine the return type.
Taking a ubyte[n] helps prevent accidentally using a swapped value
as a regular one (and in the case of floating point values, it's necessary,
because the FPU will mess up any swapped floating point values. So, you
can't actually have swapped floating point values as floating point values).
real is not supported, because its size is implementation-dependent
and therefore could vary from machine to machine (which could make it
unusable if you tried to transfer it to another machine).
littleEndianToNative, (alias template) autological_zip_eocd_scan.nativeToLittleEndian = std.bitmanip.nativeToLittleEndian(T)(const T val) if (canSwapEndianness!T)Converts the given value from the native endianness to little endian and
returns it as a ubyte[n] where n is the size of the given type.
Returning a ubyte[n] helps prevent accidentally using a swapped value
as a regular one (and in the case of floating point values, it's necessary,
because the FPU will mess up any swapped floating point values. So, you
can't actually have swapped floating point values as floating point values).
nativeToLittleEndian;
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_zip_eocd_scan.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.(package) std.digestdigest.(module) std.digest.crcCyclic Redundancy Check (32-bit) implementation.
Category Functions
| Template API | CRC CRC32 CRC64ECMA CRC64ISO |
| OOP API | CRC32Digest CRC64ECMADigest CRC64ISODigest |
| Helpers | crcHexString crc32Of crc64ECMAOf crc64ISOOf |
This module conforms to the APIs defined in std.digest. To understand the
differences between the template and the OOP API, see std.digest.
This module publicly imports std.digest and can be used as a stand-alone
module.
Note
CRCs are usually printed with the MSB first. When using
toHexString the result will be in an unexpected
order. Use toHexString's optional order parameter
to specify decreasing order for the correct result. The crcHexString
alias can also be used for this purpose.
References
Source
std/digest/crc.d
CTFE
Digests do not work in CTFE
Examples
//Template API
import std.digest.crc;
ubyte[4] hash = crc32Of("The quick brown fox jumps over the lazy dog");
assert(crcHexString(hash) == "414FA339");
//Feeding data
ubyte[1024] data;
CRC32 crc;
crc.put(data[]);
crc.start(); //Start again
crc.put(data[]);
hash = crc.finish();
//OOP API
import std.digest.crc;
auto crc = new CRC32Digest();
ubyte[] hash = crc.digest("The quick brown fox jumps over the lazy dog");
assert(crcHexString(hash) == "414FA339"); //352441c2
//Feeding data
ubyte[1024] data;
crc.put(data[]);
crc.reset(); //Start again
crc.put(data[]);
hash = crc.finish();
crc : (alias template) autological_zip_eocd_scan.crc32Of = std.digest.crc.crc32Of(T...)(T data)This is a convenience alias for digest using the
CRC32 implementation.
crc32Of;
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_zip_eocd_scan.exists = std.file.exists(R)(R name) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Determine whether the given file (or directory) exists.
exists, (alias template) autological_zip_eocd_scan.remove = std.file.remove(R)(R name) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Delete file name.
remove, (alias) autological_zip_eocd_scan.tempDir = string std.file.tempDir() @trustedReturns the path to a directory for temporary files.
On POSIX platforms, it searches through the following list of directories
and returns the first one which is found to exist:
The directory given by the TMPDIR environment variable.
The directory given by the TEMP environment variable.
The directory given by the TMP environment variable.
/tmp/
/var/tmp/
/usr/tmp/
On all platforms, tempDir returns the current working directory on failure.
The return value of the function is cached, so the procedures described
below will only be performed the first time the function is called. All
subsequent runs will return the same string, regardless of whether
environment variables and directory structures have changed in the
meantime.
The POSIX tempDir algorithm is inspired by Python's
tempfile.tempdir.
tempDir, (alias template) autological_zip_eocd_scan.write = std.file.write(R)(R name, const void[] buffer) if ((isSomeFiniteCharInputRange!R || isSomeString!R) && !isConvertibleToString!R)Write buffer to file name.
Creates the file if it does not already exist.
write;
import (package) stdstd.(module) std.pathThis module is used to manipulate path strings.
All functions, with the exception of expandTilde (and in some
cases absolutePath and relativePath), are pure
string manipulation functions; they don't depend on any state outside
the program, nor do they perform any actual file system actions.
This has the consequence that the module does not make any distinction
between a path that points to a directory and a path that points to a
file, and it does not know whether or not the object pointed to by the
path actually exists in the file system.
To differentiate between these cases, use isDir and
exists.
Note that on Windows, both the backslash (\) and the slash (/)
are in principle valid directory separators. This module treats them
both on equal footing, but in cases where a new separator is
added, a backslash will be used. Furthermore, the buildNormalizedPath
function will replace all slashes with backslashes on that platform.
In general, the functions in this module assume that the input paths
are well-formed. (That is, they should not contain invalid characters,
they should follow the file system's path format, etc.) The result
of calling a function on an ill-formed path is undefined. When there
is a chance that a path or a file name is invalid (for instance, when it
has been input by the user), it may sometimes be desirable to use the
isValidFilename and isValidPath functions to check
this.
Most functions do not perform any memory allocations, and if a string is
returned, it is usually a slice of an input string. If a function
allocates, this is explicitly mentioned in the documentation.
Category Functions Normalization absolutePath asAbsolutePath asNormalizedPath asRelativePath buildNormalizedPath buildPath chainPath expandTilde Partitioning baseName dirName dirSeparator driveName pathSeparator pathSplitter relativePath rootName stripDrive Validation isAbsolute isDirSeparator isRooted isValidFilename isValidPath Extension defaultExtension extension setExtension stripExtension withDefaultExtension withExtension Other filenameCharCmp filenameCmp globMatch CaseSensitive
Source
std/path.d
path : (alias template) autological_zip_eocd_scan.buildPath = std.path.buildPath(Range)(scope Range segments) if (isInputRange!Range && !isInfinite!Range && isSomeString!(ElementType!Range))Combines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
buildPath;
import (package) stdstd.(module) std.processFunctions for starting and interacting with other processes, and for
working with the current process' execution environment.
Process handling
`spawnProcess` spawns a new `process`, optionally assigning it an
arbitrary set of standard input, output, and error streams.
The function returns immediately, leaving the child process to execute
in parallel with its parent. All other functions in this module that
spawn processes are built around spawnProcess.
`wait` makes the parent `process` wait for a child `process` to
terminate. In general one should always do this, to avoid
child processes becoming "zombies" when the parent process exits.
Scope guards are perfect for this – see the spawnProcess
documentation for examples. tryWait is similar to wait,
but does not block if the process has not yet terminated.
`pipeProcess` also spawns a child `process` which runs
in parallel with its parent. However, instead of taking
arbitrary streams, it automatically creates a set of
pipes that allow the parent to communicate with the child
through the child's standard input, output, and/or error streams.
This function corresponds roughly to C's popen function.
`execute` starts a new `process` and waits for it
to complete before returning. Additionally, it captures
the process' standard output and error streams and returns
the output of these as a string.
`spawnShell`, `pipeShell` and `executeShell` work like
spawnProcess, pipeProcess and execute, respectively,
except that they take a single command string and run it through
the current user's default command interpreter.
executeShell corresponds roughly to C's system function.
`kill` attempts to terminate a running `process`.
The following table compactly summarises the different process creation
functions and how they relate to each other:
Runs program directly
Runs shell command Low-level process creation spawnProcess spawnShell Automatic input/output redirection using pipes pipeProcess pipeShell Execute and wait for completion, collect output execute executeShell
Other functionality
`pipe` is used to create unidirectional pipes.
`environment` is an interface through which the current `process`'
environment variables can be read and manipulated.
`escapeShellCommand` and `escapeShellFileName` are useful
for constructing shell command lines in a portable way.
Source
std/process.d
Note
Most of the functionality in this module is not available on iOS, tvOS
and watchOS. The only functions available on those platforms are:
environment, thisProcessID and thisThreadID.
process : (alias) autological_zip_eocd_scan.execute = std.typecons.Tuple!(int, "status", string, "output") std.process.execute(scope const(char[])[] args, const(string[string]) env = cast(const(string[string]))null, std.process.Config config = Config(Flags.none, null, null), ulong maxOutput = 18446744073709551615LU, scope const(char)[] workDir = null) @safeExecutes the given program or shell command and returns its exit
code and output.
execute and executeShell start a new process using
spawnProcess and spawnShell, respectively, and wait
for the process to complete before returning. The functions capture
what the child process prints to both its standard output and
standard error streams, and return this together with its exit code.
auto dmd = execute(["dmd", "myapp.d"]);
if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);
auto ls = executeShell("ls -l");
if (ls.status != 0) writeln("Failed to retrieve file listing");
else writeln(ls.output);
The args/program/command, env and config
parameters are forwarded straight to the underlying spawn functions,
and we refer to their documentation for details.
POSIX specific
If the process is terminated by a signal, the status field of
the return value will contain a negative number whose absolute
value is the signal number. (See wait for details.)
execute, (struct) std.process.ConfigOptions that control the behaviour of process creation functions in this
module. Most options only apply to spawnProcess and
spawnShell.
Example
auto logFile = File("myapp_error.log", "w");
// Start program, suppressing the console window (Windows only),
// redirect its error stream to logFile, and leave logFile open
// in the parent process as well.
auto pid = spawnProcess("myapp", stdin, stdout, logFile,
Config.retainStderr | Config.suppressConsole);
scope(exit)
{
auto exitCode = wait(pid);
logFile.writeln("myapp exited with code ", exitCode);
logFile.close();
}
Config;
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 : (struct) std.stdio.FileEncapsulates a FILE*. Generally D does not attempt to provide
thin wrappers over equivalent functions in the C standard library, but
manipulating FILE* values directly is unsafe and error-prone in
many ways. The File type ensures safe manipulation, automatic
file closing, and a lot of convenience.
The underlying FILE* handle is maintained in a reference-counted
manner, such that as soon as the last File variable bound to a
given FILE* goes out of scope, the underlying FILE* is
automatically closed.
Example
// test.d
import std.stdio;
void main(string[] args)
{
auto f = File("test.txt", "w"); // open for writing
f.write("Hello");
if (args.length > 1)
{
auto g = f; // now g and f write to the same file
// internal reference count is 2
g.write(", ", args[1]);
// g exits scope, reference count decreases to 1
}
f.writeln("!");
// f exits scope, reference count falls to zero,
// underlying `FILE*` is closed.
}
% rdmd test.d Jimmy
% cat test.txt
Hello, Jimmy!
% _
File, (alias template) autological_zip_eocd_scan.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))Equivalent to writef(fmt, args, '\n').
writefln, (alias template) autological_zip_eocd_scan.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_zip_eocd_scan.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;
/// One member of the archive we are about to synthesize.
struct (struct) autological_zip_eocd_scan.MemberOne member of the archive we are about to synthesize.
Member
{
(alias) object.string = stringstring (field) string autological_zip_eocd_scan.Member.namename;
(alias) object.string = stringstring (field) string autological_zip_eocd_scan.Member.contentscontents;
}
/// Where a member's local header ended up, so the central directory can point at it.
struct (struct) autological_zip_eocd_scan.PlacedWhere a member's local header ended up, so the central directory can point at it.
Placed
{
(struct) autological_zip_eocd_scan.MemberOne member of the archive we are about to synthesize.
Member (field) autological_zip_eocd_scan.Member autological_zip_eocd_scan.Placed.membermember;
uint (field) uint autological_zip_eocd_scan.Placed.localHeaderOffsetlocalHeaderOffset;
uint (field) uint autological_zip_eocd_scan.Placed.crccrc;
}
private enum uint (constant) uint autological_zip_eocd_scan.sigLocal = 67324752usigLocal = 0x0403_4b50; // "PK\x03\x04"
private enum uint (constant) uint autological_zip_eocd_scan.sigCentral = 33639248usigCentral = 0x0201_4b50; // "PK\x01\x02"
private enum uint (constant) uint autological_zip_eocd_scan.sigEocd = 101010256usigEocd = 0x0605_4b50; // "PK\x05\x06"
/// Appends `value` to `w` in little-endian order, the only byte order ZIP uses.
void void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE(T, W)(ref (alias) W = std.array.Appender!(ubyte[])W (parameter) std.array.Appender!(ubyte[]) ww, (alias) T = ushortT (parameter) ushort valuevalue)
{
(parameter) std.array.Appender!(ubyte[]) ww ~= ubyte[2] std.bitmanip.nativeToLittleEndian!ushort(const(ushort) val) pure nothrow @nogc @trustedConverts the given value from the native endianness to little endian and
returns it as a ubyte[n] where n is the size of the given type.
Returning a ubyte[n] helps prevent accidentally using a swapped value
as a regular one (and in the case of floating point values, it's necessary,
because the FPU will mess up any swapped floating point values. So, you
can't actually have swapped floating point values as floating point values).
Examples
int i = 12345;
ubyte[4] swappedI = nativeToLittleEndian(i);
assert(i == littleEndianToNative!int(swappedI));
float f = 123.45f;
ubyte[4] swappedF = nativeToLittleEndian(f);
assert(f == littleEndianToNative!float(swappedF));
const float cf = 123.45f;
ubyte[4] swappedCF = nativeToLittleEndian(cf);
assert(cf == littleEndianToNative!float(swappedCF));
double d = 123.45;
ubyte[8] swappedD = nativeToLittleEndian(d);
assert(d == littleEndianToNative!double(swappedD));
const double cd = 123.45;
ubyte[8] swappedCD = nativeToLittleEndian(cd);
assert(cd == littleEndianToNative!double(swappedCD));
nativeToLittleEndian((parameter) ushort valuevalue)[];
}
/// Reads a little-endian `T` at `offset` from `bytes`.
(alias) T = uintT uint autological_zip_eocd_scan.readLE!uint(in ubyte[] bytes, ulong offset) pure nothrow @nogc @safeReads a little-endian T at offset from bytes.
readLE(T)(in ubyte[] (parameter) const(ubyte[]) bytesbytes, (alias) object.size_t = ulongsize_t (parameter) ulong offsetoffset)
in ((parameter) ulong offsetoffset + (uint) uintT.(constant) ulong uint.sizeof = 4LUsizeof <= (parameter) const(ubyte[]) bytesbytes.(field) ulong const(ubyte[]).lengthlength, "read past end of buffer")
{
ubyte[(alias) T = uintT.sizeof] (local variable) ubyte[4] rawraw = (parameter) const(ubyte[]) bytesbytes[(parameter) ulong offsetoffset .. (parameter) ulong offsetoffset + (uint) uintT.(constant) ulong uint.sizeof = 4LUsizeof];
return uint std.bitmanip.littleEndianToNative!(uint, 4LU)(ubyte[4] val) pure nothrow @nogc @trustedConverts the given value from little endian to the native endianness and
returns it. The value is given as a ubyte[n] where n is the size
of the target type. You must give the target type as a template argument,
because there are multiple types with the same size and so the type of the
argument is not enough to determine the return type.
Taking a ubyte[n] helps prevent accidentally using a swapped value
as a regular one (and in the case of floating point values, it's necessary,
because the FPU will mess up any swapped floating point values. So, you
can't actually have swapped floating point values as floating point values).
real is not supported, because its size is implementation-dependent
and therefore could vary from machine to machine (which could make it
unusable if you tried to transfer it to another machine).
Examples
ushort i = 12345;
ubyte[2] swappedI = nativeToLittleEndian(i);
assert(i == littleEndianToNative!ushort(swappedI));
dchar c = 'D';
ubyte[4] swappedC = nativeToLittleEndian(c);
assert(c == littleEndianToNative!dchar(swappedC));
littleEndianToNative!(alias) T = uintT((local variable) ubyte[4] rawraw);
}
/++
Builds a `STORED` ZIP whose internal offsets are biased by `prefixLength`.
Passing a non-zero `prefixLength` is the whole trick: the archive is written as
if it already began that many bytes into the file, so gluing it after an
unrelated payload of exactly that size produces a file both readers accept.
+/
ubyte[] ubyte[] autological_zip_eocd_scan.buildZip(in autological_zip_eocd_scan.Member[] members, uint prefixLength) @safeBuilds a STORED ZIP whose internal offsets are biased by prefixLength.
Passing a non-zero prefixLength is the whole trick: the archive is written as
if it already began that many bytes into the file, so gluing it after an
unrelated payload of exactly that size produces a file both readers accept.
buildZip(in (struct) autological_zip_eocd_scan.MemberOne member of the archive we are about to synthesize.
Member[] (parameter) const(autological_zip_eocd_scan.Member[]) membersmembers, uint (parameter) uint prefixLengthprefixLength) @safe
{
auto (local variable) std.array.Appender!(ubyte[]) body_body_ = std.array.Appender!(ubyte[]) std.array.appender!(ubyte[])() pure nothrow @safeConvenience function that returns an Appender instance,
optionally initialized with array.
appender!(ubyte[]);
(struct) autological_zip_eocd_scan.PlacedWhere a member's local header ended up, so the central directory can point at it.
Placed[] (local variable) autological_zip_eocd_scan.Placed[] placedplaced;
foreach ((parameter) const(autological_zip_eocd_scan.Member) mm; (parameter) const(autological_zip_eocd_scan.Member[]) membersmembers)
{
const (local variable) const(immutable(ubyte)[]) datadata = (local variable) const(autological_zip_eocd_scan.Member) mm.(field) string autological_zip_eocd_scan.Member.contentscontents.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;
const (local variable) const(uint) crccrc = () @trusted { return uint std.bitmanip.littleEndianToNative!(uint, 4LU)(ubyte[4] val) pure nothrow @nogc @trustedConverts the given value from little endian to the native endianness and
returns it. The value is given as a ubyte[n] where n is the size
of the target type. You must give the target type as a template argument,
because there are multiple types with the same size and so the type of the
argument is not enough to determine the return type.
Taking a ubyte[n] helps prevent accidentally using a swapped value
as a regular one (and in the case of floating point values, it's necessary,
because the FPU will mess up any swapped floating point values. So, you
can't actually have swapped floating point values as floating point values).
real is not supported, because its size is implementation-dependent
and therefore could vary from machine to machine (which could make it
unusable if you tried to transfer it to another machine).
Examples
ushort i = 12345;
ubyte[2] swappedI = nativeToLittleEndian(i);
assert(i == littleEndianToNative!ushort(swappedI));
dchar c = 'D';
ubyte[4] swappedC = nativeToLittleEndian(c);
assert(c == littleEndianToNative!dchar(swappedC));
littleEndianToNative!uint(ubyte[4] std.digest.crc.crc32Of!(immutable(ubyte)[])(immutable(ubyte)[] __param_0) pure nothrow @nogc @safeThis is a convenience alias for digest using the
CRC32 implementation.
Examples
ubyte[] data = [4,5,7,25];
assert(data.crc32Of == [167, 180, 199, 131]);
import std.utf : byChar;
assert("hello"d.byChar.crc32Of == [134, 166, 16, 54]);
ubyte[4] hash = "abc".crc32Of();
assert(hash == digest!CRC32("ab", "c"));
import std.range : iota;
enum ubyte S = 5, F = 66;
assert(iota(S, F).crc32Of == [59, 140, 234, 154]);
crc32Of((local variable) const(immutable(ubyte)[]) datadata)); }();
(local variable) autological_zip_eocd_scan.Placed[] placedplaced ~= (struct) autological_zip_eocd_scan.PlacedWhere a member's local header ended up, so the central directory can point at it.
Placed((local variable) const(autological_zip_eocd_scan.Member) mm, (parameter) uint prefixLengthprefixLength + cast(uint) (local variable) std.array.Appender!(ubyte[]) body_body_[].(field) ulong ubyte[].lengthlength, (local variable) const(uint) crccrc);
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, (constant) uint autological_zip_eocd_scan.sigLocal = 67324752usigLocal);
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, ushort(20)); // version needed to extract: 2.0
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, ushort(0)); // general purpose bit flag
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, ushort(0)); // compression method: 0 = STORED
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, ushort(0)); // last mod time (fixed, for reproducibility)
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, ushort(0x21)); // last mod date: 1980-01-01
void autological_zip_eocd_scan.putLE!(const(uint), std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, const(uint) value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, (local variable) const(uint) crccrc);
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, cast(uint) (local variable) const(immutable(ubyte)[]) datadata.(field) ulong const(immutable(ubyte)[]).lengthlength); // compressed size
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, cast(uint) (local variable) const(immutable(ubyte)[]) datadata.(field) ulong const(immutable(ubyte)[]).lengthlength); // uncompressed size
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, cast(ushort) (local variable) const(autological_zip_eocd_scan.Member) mm.(field) string autological_zip_eocd_scan.Member.namename.(field) ulong const(string).lengthlength);
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) body_body_, ushort(0)); // extra field length
(local variable) std.array.Appender!(ubyte[]) body_body_ ~= (local variable) const(autological_zip_eocd_scan.Member) mm.(field) string autological_zip_eocd_scan.Member.namename.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) std.array.Appender!(ubyte[]) body_body_ ~= (local variable) const(immutable(ubyte)[]) datadata;
}
const (local variable) const(uint) centralOffsetcentralOffset = (parameter) uint prefixLengthprefixLength + cast(uint) (local variable) std.array.Appender!(ubyte[]) body_body_[].(field) ulong ubyte[].lengthlength;
auto (local variable) std.array.Appender!(ubyte[]) centralcentral = std.array.Appender!(ubyte[]) std.array.appender!(ubyte[])() pure nothrow @safeConvenience function that returns an Appender instance,
optionally initialized with array.
appender!(ubyte[]);
foreach ((parameter) autological_zip_eocd_scan.Placed pp; (local variable) autological_zip_eocd_scan.Placed[] placedplaced)
{
const (local variable) const(immutable(ubyte)[]) datadata = (local variable) autological_zip_eocd_scan.Placed pp.(field) autological_zip_eocd_scan.Member autological_zip_eocd_scan.Placed.membermember.(field) string autological_zip_eocd_scan.Member.contentscontents.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;
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, (constant) uint autological_zip_eocd_scan.sigCentral = 33639248usigCentral);
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, ushort(20)); // version made by
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, ushort(20)); // version needed to extract
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, ushort(0)); // flags
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, ushort(0)); // method: STORED
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, ushort(0)); // time
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, ushort(0x21)); // date
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, (local variable) autological_zip_eocd_scan.Placed pp.(field) uint autological_zip_eocd_scan.Placed.crccrc);
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, cast(uint) (local variable) const(immutable(ubyte)[]) datadata.(field) ulong const(immutable(ubyte)[]).lengthlength);
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, cast(uint) (local variable) const(immutable(ubyte)[]) datadata.(field) ulong const(immutable(ubyte)[]).lengthlength);
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, cast(ushort) (local variable) autological_zip_eocd_scan.Placed pp.(field) autological_zip_eocd_scan.Member autological_zip_eocd_scan.Placed.membermember.(field) string autological_zip_eocd_scan.Member.namename.(field) ulong string.lengthlength);
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, ushort(0)); // extra length
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, ushort(0)); // comment length
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, ushort(0)); // disk number start
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, ushort(0)); // internal attributes
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, uint(0)); // external attributes
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) centralcentral, (local variable) autological_zip_eocd_scan.Placed pp.(field) uint autological_zip_eocd_scan.Placed.localHeaderOffsetlocalHeaderOffset); // <-- biased by the prefix
(local variable) std.array.Appender!(ubyte[]) centralcentral ~= (local variable) autological_zip_eocd_scan.Placed pp.(field) autological_zip_eocd_scan.Member autological_zip_eocd_scan.Placed.membermember.(field) string autological_zip_eocd_scan.Member.namename.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;
}
auto (local variable) std.array.Appender!(ubyte[]) eocdeocd = std.array.Appender!(ubyte[]) std.array.appender!(ubyte[])() pure nothrow @safeConvenience function that returns an Appender instance,
optionally initialized with array.
appender!(ubyte[]);
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) eocdeocd, (constant) uint autological_zip_eocd_scan.sigEocd = 101010256usigEocd);
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) eocdeocd, ushort(0)); // this disk
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) eocdeocd, ushort(0)); // disk with central directory
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) eocdeocd, cast(ushort) (local variable) autological_zip_eocd_scan.Placed[] placedplaced.(field) ulong autological_zip_eocd_scan.Placed[].lengthlength); // entries on this disk
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) eocdeocd, cast(ushort) (local variable) autological_zip_eocd_scan.Placed[] placedplaced.(field) ulong autological_zip_eocd_scan.Placed[].lengthlength); // entries total
void autological_zip_eocd_scan.putLE!(uint, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, uint value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) eocdeocd, cast(uint) (local variable) std.array.Appender!(ubyte[]) centralcentral[].(field) ulong ubyte[].lengthlength); // central directory size
void autological_zip_eocd_scan.putLE!(const(uint), std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, const(uint) value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) eocdeocd, (local variable) const(uint) centralOffsetcentralOffset); // <-- biased by the prefix
void autological_zip_eocd_scan.putLE!(ushort, std.array.Appender!(ubyte[]))(ref std.array.Appender!(ubyte[]) w, ushort value) pure nothrow @safeAppends value to w in little-endian order, the only byte order ZIP uses.
putLE((local variable) std.array.Appender!(ubyte[]) eocdeocd, ushort(0)); // comment length
return (local variable) std.array.Appender!(ubyte[]) body_body_[] ~ (local variable) std.array.Appender!(ubyte[]) centralcentral[] ~ (local variable) std.array.Appender!(ubyte[]) eocdeocd[];
}
/// What a tail-only read recovered, plus what it cost.
struct (struct) autological_zip_eocd_scan.EnumeratedWhat a tail-only read recovered, plus what it cost.
Enumerated
{
(alias) object.string = stringstring[] (field) string[] autological_zip_eocd_scan.Enumerated.namesnames;
uint (field) uint autological_zip_eocd_scan.Enumerated.centralOffsetcentralOffset;
uint (field) uint autological_zip_eocd_scan.Enumerated.centralSizecentralSize;
uint (field) uint autological_zip_eocd_scan.Enumerated.firstLocalHeaderOffsetfirstLocalHeaderOffset;
(alias) object.size_t = ulongsize_t (field) ulong autological_zip_eocd_scan.Enumerated.bytesReadbytesRead;
}
/++
Enumerates an archive by doing what a real reader does: seek to the end, scan
backwards for the EOCD signature, then read only the central directory.
Never reads a local file header, and never reads a byte of file data — which is
why the returned `bytesRead` is a small constant plus the directory size,
independent of how large the members (or the parasitic prefix) are.
+/
(struct) autological_zip_eocd_scan.EnumeratedWhat a tail-only read recovered, plus what it cost.
Enumerated autological_zip_eocd_scan.Enumerated autological_zip_eocd_scan.enumerateFromTail(string path, ulong tailWindow = 512LU)Enumerates an archive by doing what a real reader does: seek to the end, scan
backwards for the EOCD signature, then read only the central directory.
Never reads a local file header, and never reads a byte of file data — which is
why the returned bytesRead is a small constant plus the directory size,
independent of how large the members (or the parasitic prefix) are.
enumerateFromTail((alias) object.string = stringstring (parameter) string pathpath, (alias) object.size_t = ulongsize_t (parameter) ulong tailWindowtailWindow = 512)
{
auto (local variable) std.stdio.File ff = (struct) std.stdio.FileEncapsulates a FILE*. Generally D does not attempt to provide
thin wrappers over equivalent functions in the C standard library, but
manipulating FILE* values directly is unsafe and error-prone in
many ways. The File type ensures safe manipulation, automatic
file closing, and a lot of convenience.
The underlying FILE* handle is maintained in a reference-counted
manner, such that as soon as the last File variable bound to a
given FILE* goes out of scope, the underlying FILE* is
automatically closed.
Example
// test.d
import std.stdio;
void main(string[] args)
{
auto f = File("test.txt", "w"); // open for writing
f.write("Hello");
if (args.length > 1)
{
auto g = f; // now g and f write to the same file
// internal reference count is 2
g.write(", ", args[1]);
// g exits scope, reference count decreases to 1
}
f.writeln("!");
// f exits scope, reference count falls to zero,
// underlying `FILE*` is closed.
}
% rdmd test.d Jimmy
% cat test.txt
Hello, Jimmy!
% _
File(std.stdio.File std.stdio.File.this(string name, scope const(char)[] stdioOpenmode = "rb") ref @safeConstructor taking the name of the file to open and the open mode.
Copying one File object to another results in the two File
objects referring to the same underlying file.
The destructor automatically closes the file as soon as no File
object refers to it anymore.
path, "rb");
const (local variable) const(ulong) sizesize = (local variable) std.stdio.File ff.ulong std.stdio.File.size() @property @safeReturns the size of the file in bytes, ulong.max if file is not searchable or throws if the operation fails.
Example
import std.stdio, std.file;
void main()
{
string deleteme = "delete.me";
auto file_handle = File(deleteme, "w");
file_handle.write("abc"); //create temporary file
scope(exit) deleteme.remove; //remove temporary file at scope exit
assert(file_handle.size() == 3); //check if file size is 3 bytes
}
size;
(alias) object.size_t = ulongsize_t (local variable) ulong bytesReadbytesRead;
const (local variable) const(ulong) windowwindow = (local variable) const(ulong) sizesize < (parameter) ulong tailWindowtailWindow ? cast((alias) object.size_t = ulongsize_t) (local variable) const(ulong) sizesize : (parameter) ulong tailWindowtailWindow;
(local variable) std.stdio.File ff.void std.stdio.File.seek(long offset, int origin = 0) @trustedCalls fseek
for the file handle to move its position indicator.
seek(cast(long)((local variable) const(ulong) sizesize - (local variable) const(ulong) windowwindow));
auto (local variable) ubyte[] tailtail = new ubyte[(local variable) const(ulong) windowwindow];
(local variable) ubyte[] tailtail = (local variable) std.stdio.File ff.ubyte[] std.stdio.File.rawRead!ubyte(ubyte[] buffer) @safeCalls fread for the
file handle. The number of items to read and the size of
each item is inferred from the size and type of the input array, respectively.
Examples
static import std.file;
auto testFile = std.file.deleteme();
std.file.write(testFile, "\r\n\n\r\n");
scope(exit) std.file.remove(testFile);
auto f = File(testFile, "r");
auto buf = f.rawRead(new char[5]);
f.close();
assert(buf == "\r\n\n\r\n");
rawRead((local variable) ubyte[] tailtail);
(local variable) ulong bytesReadbytesRead += (local variable) ubyte[] tailtail.(field) ulong ubyte[].lengthlength;
// Backwards scan: the EOCD is last, but a trailing comment may follow it,
// so the signature — not the file end — is the anchor.
(alias) object.ptrdiff_t = longptrdiff_t (local variable) long eocdeocd = -1;
for ((alias) object.ptrdiff_t = longptrdiff_t (local variable) long ii = cast((alias) object.ptrdiff_t = longptrdiff_t) (local variable) ubyte[] tailtail.(field) ulong ubyte[].lengthlength - 22; i >= 0; i--)
{
if (uint autological_zip_eocd_scan.readLE!uint(in ubyte[] bytes, ulong offset) pure nothrow @nogc @safeReads a little-endian T at offset from bytes.
readLE!uint((local variable) ubyte[] tailtail, (local variable) long ii) == (constant) uint autological_zip_eocd_scan.sigEocd = 101010256usigEocd)
{
(local variable) long eocdeocd = (local variable) long ii;
break;
}
}
if ((local variable) long eocdeocd < 0)
throw new (class) object.ExceptionThe base class of all errors that are safe to catch and handle.
In principle, only thrown objects derived from this class are safe to catch
inside a catch block. Thrown objects not derived from Exception
represent runtime errors that should not be caught, as certain runtime
guarantees may not hold, making it unsafe to continue program execution.
Examples
bool gotCaught;
try
{
throw new Exception("msg");
}
catch (Exception e)
{
gotCaught = true;
assert(e.msg == "msg");
}
assert(gotCaught);
Exception("no End Of Central Directory record in the last " ~ (local variable) const(ulong) windowwindow.string std.conv.text!(const(ulong))(const(ulong) __param_0) pure nothrow @safeConvenience functions for converting one or more arguments
of any type into text (the three character widths).
text ~ " bytes");
const (local variable) const(ushort) totaltotal = ushort autological_zip_eocd_scan.readLE!ushort(in ubyte[] bytes, ulong offset) pure nothrow @nogc @safeReads a little-endian T at offset from bytes.
readLE!ushort((local variable) ubyte[] tailtail, (local variable) long eocdeocd + 10);
const (local variable) const(uint) centralSizecentralSize = uint autological_zip_eocd_scan.readLE!uint(in ubyte[] bytes, ulong offset) pure nothrow @nogc @safeReads a little-endian T at offset from bytes.
readLE!uint((local variable) ubyte[] tailtail, (local variable) long eocdeocd + 12);
const (local variable) const(uint) centralOffsetcentralOffset = uint autological_zip_eocd_scan.readLE!uint(in ubyte[] bytes, ulong offset) pure nothrow @nogc @safeReads a little-endian T at offset from bytes.
readLE!uint((local variable) ubyte[] tailtail, (local variable) long eocdeocd + 16);
(local variable) std.stdio.File ff.void std.stdio.File.seek(long offset, int origin = 0) @trustedCalls fseek
for the file handle to move its position indicator.
seek((local variable) const(uint) centralOffsetcentralOffset);
auto (local variable) ubyte[] centralcentral = new ubyte[(local variable) const(uint) centralSizecentralSize];
(local variable) ubyte[] centralcentral = (local variable) std.stdio.File ff.ubyte[] std.stdio.File.rawRead!ubyte(ubyte[] buffer) @safeCalls fread for the
file handle. The number of items to read and the size of
each item is inferred from the size and type of the input array, respectively.
Examples
static import std.file;
auto testFile = std.file.deleteme();
std.file.write(testFile, "\r\n\n\r\n");
scope(exit) std.file.remove(testFile);
auto f = File(testFile, "r");
auto buf = f.rawRead(new char[5]);
f.close();
assert(buf == "\r\n\n\r\n");
rawRead((local variable) ubyte[] centralcentral);
(local variable) ulong bytesReadbytesRead += (local variable) ubyte[] centralcentral.(field) ulong ubyte[].lengthlength;
(alias) object.string = stringstring[] (local variable) string[] namesnames;
uint (local variable) uint firstLocalfirstLocal;
(alias) object.size_t = ulongsize_t (local variable) ulong cursorcursor;
foreach ((local variable) int ii; 0 .. (local variable) const(ushort) totaltotal)
{
if (uint autological_zip_eocd_scan.readLE!uint(in ubyte[] bytes, ulong offset) pure nothrow @nogc @safeReads a little-endian T at offset from bytes.
readLE!uint((local variable) ubyte[] centralcentral, (local variable) ulong cursorcursor) != (constant) uint autological_zip_eocd_scan.sigCentral = 33639248usigCentral)
throw new (class) object.ExceptionThe base class of all errors that are safe to catch and handle.
In principle, only thrown objects derived from this class are safe to catch
inside a catch block. Thrown objects not derived from Exception
represent runtime errors that should not be caught, as certain runtime
guarantees may not hold, making it unsafe to continue program execution.
Examples
bool gotCaught;
try
{
throw new Exception("msg");
}
catch (Exception e)
{
gotCaught = true;
assert(e.msg == "msg");
}
assert(gotCaught);
Exception("central directory entry has a bad signature");
const (local variable) const(ushort) nameLennameLen = ushort autological_zip_eocd_scan.readLE!ushort(in ubyte[] bytes, ulong offset) pure nothrow @nogc @safeReads a little-endian T at offset from bytes.
readLE!ushort((local variable) ubyte[] centralcentral, (local variable) ulong cursorcursor + 28);
const (local variable) const(ushort) extraLenextraLen = ushort autological_zip_eocd_scan.readLE!ushort(in ubyte[] bytes, ulong offset) pure nothrow @nogc @safeReads a little-endian T at offset from bytes.
readLE!ushort((local variable) ubyte[] centralcentral, (local variable) ulong cursorcursor + 30);
const (local variable) const(ushort) commentLencommentLen = ushort autological_zip_eocd_scan.readLE!ushort(in ubyte[] bytes, ulong offset) pure nothrow @nogc @safeReads a little-endian T at offset from bytes.
readLE!ushort((local variable) ubyte[] centralcentral, (local variable) ulong cursorcursor + 32);
if ((local variable) int ii == 0)
(local variable) uint firstLocalfirstLocal = uint autological_zip_eocd_scan.readLE!uint(in ubyte[] bytes, ulong offset) pure nothrow @nogc @safeReads a little-endian T at offset from bytes.
readLE!uint((local variable) ubyte[] centralcentral, (local variable) ulong cursorcursor + 42);
(local variable) string[] namesnames ~= cast((alias) object.string = stringstring) (local variable) ubyte[] centralcentral[(local variable) ulong cursorcursor + 46 .. (local variable) ulong cursorcursor + 46 + (local variable) const(ushort) nameLennameLen].immutable(ubyte)[] object.idup!ubyte(ubyte[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
(local variable) ulong cursorcursor += 46 + (local variable) const(ushort) nameLennameLen + (local variable) const(ushort) extraLenextraLen + (local variable) const(ushort) commentLencommentLen;
}
return (struct) autological_zip_eocd_scan.EnumeratedWhat a tail-only read recovered, plus what it cost.
Enumerated((local variable) string[] namesnames, (local variable) const(uint) centralOffsetcentralOffset, (local variable) const(uint) centralSizecentralSize, (local variable) uint firstLocalfirstLocal, (local variable) ulong bytesReadbytesRead);
}
int int D main()main()
{
// The parasitic prefix. In redbean this is a real PE/ELF/Mach-O image; the
// ZIP format cannot tell the difference and does not try to.
const (local variable) const(string) prefixprefix = "#!/bin/sh\n" ~
"# Everything above the archive is opaque to a ZIP reader.\n" ~
"echo 'this file is also a shell script'; exit 0\n";
// One member is deliberately bulky. Enumeration must not touch it: that is
// the difference between an index you can range-request and one you cannot.
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) replicate = std.array.replicate(S)(S s, size_t n) if (isDynamicArray!S)Params:
s = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
or a dynamic array
n = number of times to repeat s
Returns:
An array that consists of s repeated n times. This function allocates, fills, and
returns a new array.
See_Also:
For a lazy version, refer to $(REF repeat, std,range).
replicate;
const (local variable) const(autological_zip_eocd_scan.Member[]) membersmembers = [
(struct) autological_zip_eocd_scan.MemberOne member of the archive we are about to synthesize.
Member("greeting.txt", "the container is a tax\n"),
(struct) autological_zip_eocd_scan.MemberOne member of the archive we are about to synthesize.
Member("assets/note.md", "# footer-anchored\n\nThe index is at the end, so the front is free.\n"),
(struct) autological_zip_eocd_scan.MemberOne member of the archive we are about to synthesize.
Member("assets/bulk.bin", string std.array.replicate!string(string s, ulong n) pure nothrow @safereplicate("payload ", 32 * 1024)),
];
const (local variable) const(ubyte[]) zipzip = ubyte[] autological_zip_eocd_scan.buildZip(in autological_zip_eocd_scan.Member[] members, uint prefixLength) @safeBuilds a STORED ZIP whose internal offsets are biased by prefixLength.
Passing a non-zero prefixLength is the whole trick: the archive is written as
if it already began that many bytes into the file, so gluing it after an
unrelated payload of exactly that size produces a file both readers accept.
buildZip((local variable) const(autological_zip_eocd_scan.Member[]) membersmembers, cast(uint) (local variable) const(string) prefixprefix.(field) ulong const(string).lengthlength);
const (local variable) const(string) pathpath = string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath(string std.file.tempDir() @trustedReturns the path to a directory for temporary files.
On POSIX platforms, it searches through the following list of directories
and returns the first one which is found to exist:
The directory given by the TMPDIR environment variable.
The directory given by the TEMP environment variable.
The directory given by the TMP environment variable.
/tmp/
/var/tmp/
/usr/tmp/
On all platforms, tempDir returns the current working directory on failure.
The return value of the function is cached, so the procedures described
below will only be performed the first time the function is called. All
subsequent runs will return the same string, regardless of whether
environment variables and directory structures have changed in the
meantime.
The POSIX tempDir algorithm is inspired by Python's
tempfile.tempdir.
Examples
import std.ascii : letters;
import std.conv : to;
import std.path : buildPath;
import std.random : randomSample;
import std.utf : byCodeUnit;
// random id with 20 letters
auto id = letters.byCodeUnit.randomSample(20).to!string;
auto myFile = tempDir.buildPath(id ~ "my_tmp_file");
scope(exit) myFile.remove;
myFile.write("hello");
assert(myFile.readText == "hello");
tempDir, "autological-polyglot.zip");
void std.file.write!string(string name, const(void[]) buffer) @safeWrite buffer to file name.
Creates the file if it does not already exist.
Examples
scope(exit)
{
assert(exists(deleteme));
remove(deleteme);
}
int[] a = [ 0, 1, 1, 2, 3, 5, 8 ];
write(deleteme, a); // deleteme is the name of a temporary file
const bytes = read(deleteme);
const fileInts = () @trusted { return cast(int[]) bytes; }();
assert(fileInts == a);
write((local variable) const(string) pathpath, (local variable) const(string) prefixprefix.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) const(ubyte[]) zipzip);
scope (exit)
if ((local variable) const(string) pathpath.bool std.file.exists!string(string name) nothrow @nogc @safeDetermine whether the given file (or directory) exists.
exists)
void std.file.remove!string(string name) @safeDelete file name.
remove((local variable) const(string) pathpath);
const (local variable) const(ulong) totaltotal = (local variable) const(string) prefixprefix.(field) ulong const(string).lengthlength + (local variable) const(ubyte[]) zipzip.(field) ulong const(ubyte[]).lengthlength;
void std.stdio.writefln!(char, const(ulong), ulong, ulong)(in char[] fmt, const(ulong) __param_1, ulong __param_2, ulong __param_3) @safeEquivalent to writef(fmt, args, '\n').
writefln("Built a %s-byte polyglot: %s bytes of shell script, then a %s-byte ZIP.",
(local variable) const(ulong) totaltotal, (local variable) const(string) prefixprefix.(field) ulong const(string).lengthlength, (local variable) const(ubyte[]) zipzip.(field) ulong const(ubyte[]).lengthlength);
void std.stdio.writefln!(char, char)(in char[] fmt, char __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln(" byte 0 is '%s' — a ZIP reader never looks there.", cast(char) (local variable) const(string) prefixprefix[0]);
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;
const (local variable) const(autological_zip_eocd_scan.Enumerated) foundfound = autological_zip_eocd_scan.Enumerated autological_zip_eocd_scan.enumerateFromTail(string path, ulong tailWindow = 512LU)Enumerates an archive by doing what a real reader does: seek to the end, scan
backwards for the EOCD signature, then read only the central directory.
Never reads a local file header, and never reads a byte of file data — which is
why the returned bytesRead is a small constant plus the directory size,
independent of how large the members (or the parasitic prefix) are.
enumerateFromTail((local variable) const(string) pathpath);
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("Enumerated by scanning backwards from EOF:");
void std.stdio.writefln!(char, const(uint), const(uint))(in char[] fmt, const(uint) __param_1, const(uint) __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" central directory at absolute offset %s, %s bytes",
(local variable) const(autological_zip_eocd_scan.Enumerated) foundfound.(field) uint autological_zip_eocd_scan.Enumerated.centralOffsetcentralOffset, (local variable) const(autological_zip_eocd_scan.Enumerated) foundfound.(field) uint autological_zip_eocd_scan.Enumerated.centralSizecentralSize);
foreach ((parameter) const(string) nn; (local variable) const(autological_zip_eocd_scan.Enumerated) foundfound.(field) string[] autological_zip_eocd_scan.Enumerated.namesnames)
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln(" entry: %s", (local variable) const(string) nn);
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(" first member's local header sits at absolute offset %s == the prefix length (%s):",
(local variable) const(autological_zip_eocd_scan.Enumerated) foundfound.(field) uint autological_zip_eocd_scan.Enumerated.firstLocalHeaderOffsetfirstLocalHeaderOffset, (local variable) const(string) prefixprefix.(field) ulong const(string).lengthlength);
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(" every internal pointer is biased by the prefix, which is what `zip -A` repairs");
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 std.stdio.writefln!(char, const(ulong), const(ulong), double)(in char[] fmt, const(ulong) __param_1, const(ulong) __param_2, double __param_3) @safeEquivalent to writef(fmt, args, '\n').
writefln("Cost of enumeration: %s of %s bytes read (%.1f%%).",
(local variable) const(autological_zip_eocd_scan.Enumerated) foundfound.(field) ulong autological_zip_eocd_scan.Enumerated.bytesReadbytesRead, (local variable) const(ulong) totaltotal, 100.0 * (local variable) const(autological_zip_eocd_scan.Enumerated) foundfound.(field) ulong autological_zip_eocd_scan.Enumerated.bytesReadbytesRead / (local variable) const(ulong) totaltotal);
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(" A header-anchored format would have had to start at byte 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(" which is the byte the prefix is already using.");
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;
// An independent implementation is the real proof. `unzip -l` refuses
// nothing here: it performs the same backwards scan.
const (local variable) const(std.typecons.Tuple!(int, "status", string, "output")) probeprobe = std.typecons.Tuple!(int, "status", string, "output") std.process.execute(scope const(char[])[] args, const(string[string]) env = cast(const(string[string]))null, std.process.Config config = Config(Flags.none, null, null), ulong maxOutput = 18446744073709551615LU, scope const(char)[] workDir = null) @safeExecutes the given program or shell command and returns its exit
code and output.
execute and executeShell start a new process using
spawnProcess and spawnShell, respectively, and wait
for the process to complete before returning. The functions capture
what the child process prints to both its standard output and
standard error streams, and return this together with its exit code.
auto dmd = execute(["dmd", "myapp.d"]);
if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);
auto ls = executeShell("ls -l");
if (ls.status != 0) writeln("Failed to retrieve file listing");
else writeln(ls.output);
The args/program/command, env and config
parameters are forwarded straight to the underlying spawn functions,
and we refer to their documentation for details.
POSIX specific
If the process is terminated by a signal, the status field of
the return value will contain a negative number whose absolute
value is the signal number. (See wait for details.)
execute(["unzip", "-l", (local variable) const(string) pathpath], null, (struct) std.process.ConfigOptions that control the behaviour of process creation functions in this
module. Most options only apply to spawnProcess and
spawnShell.
Example
auto logFile = File("myapp_error.log", "w");
// Start program, suppressing the console window (Windows only),
// redirect its error stream to logFile, and leave logFile open
// in the parent process as well.
auto pid = spawnProcess("myapp", stdin, stdout, logFile,
Config.retainStderr | Config.suppressConsole);
scope(exit)
{
auto exitCode = wait(pid);
logFile.writeln("myapp exited with code ", exitCode);
logFile.close();
}
Config.(constant) std.process.Config std.process.Config.suppressConsole = Config(Flags.suppressConsole, null, null)For backwards compatibility, and cases when only flags need to
be specified in the Config, these allow building Config
instances using flag names only.
suppressConsole);
if ((local variable) const(std.typecons.Tuple!(int, "status", string, "output")) probeprobe.status == 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("System `unzip -l` agrees:");
foreach ((local variable) string lineline; (local variable) const(std.typecons.Tuple!(int, "status", string, "output")) probeprobe.output.std.string.LineSplitter!(Flag.no, string) autological_zip_eocd_scan.lineSplitterRange(string s) pure nothrow @nogc @safelineSplitter wrapped so the call site above reads as one pipeline.
lineSplitterRange)
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln(" | %s", (local variable) string lineline);
}
else
{
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 working `unzip` on PATH — the independent cross-check was not run.");
}
return 0;
}
/// `lineSplitter` wrapped so the call site above reads as one pipeline.
private auto std.string.LineSplitter!(Flag.no, string) autological_zip_eocd_scan.lineSplitterRange(string s) pure nothrow @nogc @safelineSplitter wrapped so the call site above reads as one pipeline.
lineSplitterRange((alias) object.string = stringstring (parameter) string ss) @safe pure nothrow
{
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) lineSplitter = std.string.lineSplitter(Flag keepTerm = No.keepTerminator, Range)(Range r) if (hasSlicing!Range && hasLength!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range)Split an array or slicable range of characters into a range of lines
using '\r', '\n', '\v', '\f', "\r\n",
$(REF lineSep, std,uni), $(REF paraSep, std,uni) and '\u0085' (NEL)
as delimiters. If keepTerm is set to Yes.keepTerminator, then the
delimiter is included in the slices returned.
Does not throw on invalid UTF; such is simply passed unchanged
to the output.
Adheres to $(HTTP www.unicode.org/versions/Unicode7.0.0/ch05.pdf, Unicode 7.0).
Does not allocate memory.
Params:
r = array of chars, wchars, or dchars or a slicable range
keepTerm = whether delimiter is included or not in the results
Returns:
range of slices of the input range r
See_Also:
$(LREF splitLines)
$(REF splitter, std,algorithm)
$(REF splitter, std,regex)
lineSplitter;
return (parameter) string ss.std.string.LineSplitter!(Flag.no, string) std.string.lineSplitter!(Flag.no, immutable(char))(string r) pure nothrow @nogc @safeSplit an array or slicable range of characters into a range of lines
using '\r', '\n', '\v', '\f', "\r\n",
lineSep, paraSep and '\u0085' (NEL)
as delimiters. If keepTerm is set to Yes.keepTerminator, then the
delimiter is included in the slices returned.
Does not throw on invalid UTF; such is simply passed unchanged
to the output.
Adheres to Unicode 7.0.
Does not allocate memory.
Examples
import std.array : array;
string s = "Hello\nmy\rname\nis";
/* notice the call to 'array' to turn the lazy range created by
lineSplitter comparable to the string[] created by splitLines.
*/
assert(lineSplitter(s).array == splitLines(s));
auto s = "\rpeter\n\rpaul\r\njerry\u2028ice\u2029cream\n\nsunday\nmon\u2030day\n";
auto lines = s.lineSplitter();
static immutable witness = ["", "peter", "", "paul", "jerry", "ice", "cream", "", "sunday", "mon\u2030day"];
uint i;
foreach (line; lines)
{
assert(line == witness[i++]);
}
assert(i == witness.length);
lineSplitter;
}