make @safe
, improve coverage and refresh the style
This commit is contained in:
parent
b77a3fb709
commit
edf4979207
|
@ -6,10 +6,6 @@
|
|||
/// A minimal library providing functionality for changing the endianness of data.
|
||||
module tinyendian;
|
||||
|
||||
|
||||
import core.stdc.string;
|
||||
|
||||
import std.algorithm;
|
||||
import std.system;
|
||||
import std.utf;
|
||||
|
||||
|
@ -23,8 +19,8 @@ enum UTFEncoding : ubyte
|
|||
UTF_16,
|
||||
UTF_32
|
||||
}
|
||||
|
||||
unittest
|
||||
///
|
||||
@safe unittest
|
||||
{
|
||||
const ints = [314, -101];
|
||||
int[2] intsSwapBuffer = ints;
|
||||
|
@ -39,8 +35,6 @@ unittest
|
|||
assert(floats == floatsSwapBuffer, "Lost information when swapping byte order");
|
||||
}
|
||||
|
||||
@nogc @system pure nothrow:
|
||||
|
||||
/** Swap byte order of items in an array in place.
|
||||
*
|
||||
* Params:
|
||||
|
@ -48,19 +42,20 @@ unittest
|
|||
* T = Item type. Must be either 2 or 4 bytes long.
|
||||
* array = Buffer with values to fix byte order of.
|
||||
*/
|
||||
void swapByteOrder(T)(T[] array)
|
||||
if([2, 4].canFind(T.sizeof))
|
||||
void swapByteOrder(T)(T[] array) @trusted @nogc pure nothrow
|
||||
if (T.sizeof == 2 || T.sizeof == 4)
|
||||
{
|
||||
import core.bitop;
|
||||
// Swap the byte order of all read characters.
|
||||
foreach(ref item; array)
|
||||
foreach (ref item; array)
|
||||
{
|
||||
static if(T.sizeof == 2)
|
||||
static if (T.sizeof == 2)
|
||||
{
|
||||
import std.algorithm.mutation : swap;
|
||||
swap(*cast(ubyte*)&item, *(cast(ubyte*)&item + 1));
|
||||
}
|
||||
else static if(T.sizeof == 4)
|
||||
else static if (T.sizeof == 4)
|
||||
{
|
||||
import core.bitop : bswap;
|
||||
const swapped = bswap(*cast(uint*)&item);
|
||||
item = *cast(const(T)*)&swapped;
|
||||
}
|
||||
|
@ -68,6 +63,15 @@ void swapByteOrder(T)(T[] array)
|
|||
}
|
||||
}
|
||||
|
||||
/// See fixUTFByteOrder.
|
||||
struct FixUTFByteOrderResult
|
||||
{
|
||||
ubyte[] array;
|
||||
UTFEncoding encoding;
|
||||
Endian endian;
|
||||
uint bytesStripped = 0;
|
||||
}
|
||||
|
||||
/** Convert byte order of an array encoded in UTF(8/16/32) to system endianness in place.
|
||||
*
|
||||
* Uses the UTF byte-order-mark (BOM) to determine UTF encoding. If there is no BOM
|
||||
|
@ -100,7 +104,7 @@ void swapByteOrder(T)(T[] array)
|
|||
*
|
||||
* Complexity: (BIGOH array.length)
|
||||
*/
|
||||
auto fixUTFByteOrder(ubyte[] array)
|
||||
auto fixUTFByteOrder(ubyte[] array) @safe @nogc pure nothrow
|
||||
{
|
||||
// Enumerates UTF BOMs, matching indices to byteOrderMarks/bomEndian.
|
||||
enum BOM: ubyte
|
||||
|
@ -126,23 +130,17 @@ auto fixUTFByteOrder(ubyte[] array)
|
|||
Endian.bigEndian ];
|
||||
|
||||
// Documented in function ddoc.
|
||||
struct Result
|
||||
{
|
||||
ubyte[] array;
|
||||
UTFEncoding encoding;
|
||||
Endian endian;
|
||||
uint bytesStripped = 0;
|
||||
}
|
||||
Result result;
|
||||
|
||||
FixUTFByteOrderResult result;
|
||||
|
||||
// Detect BOM, if any, in the bytes we've read. -1 means no BOM.
|
||||
// Need the last match: First 2 bytes of UTF-32LE BOM match the UTF-16LE BOM. If we
|
||||
// used the first match, UTF-16LE would be detected when we have a UTF-32LE BOM.
|
||||
import std.algorithm.searching : startsWith;
|
||||
BOM bomId = BOM.None;
|
||||
foreach(i, bom; byteOrderMarks) if(array.startsWith(bom))
|
||||
{
|
||||
foreach (i, bom; byteOrderMarks)
|
||||
if (array.startsWith(bom))
|
||||
bomId = cast(BOM)i;
|
||||
}
|
||||
|
||||
result.endian = (bomId != BOM.None) ? bomEndian[bomId] : Endian.init;
|
||||
|
||||
|
@ -168,21 +166,52 @@ auto fixUTFByteOrder(ubyte[] array)
|
|||
break;
|
||||
}
|
||||
|
||||
array = array[0 .. $ - result.bytesStripped];
|
||||
// If there's a BOM, we need to move data back to ensure it starts at array[0]
|
||||
if(start != 0)
|
||||
if (start != 0)
|
||||
{
|
||||
core.stdc.string.memmove(array.ptr, array.ptr + start, array.length - start);
|
||||
array = array[0 .. $ - start];
|
||||
array = array[start .. $ - result.bytesStripped];
|
||||
}
|
||||
|
||||
// We enforce above that array.length is divisible by 2/4 for UTF-16/32
|
||||
if(std.system.endian != result.endian)
|
||||
if (std.system.endian != result.endian)
|
||||
{
|
||||
if(result.encoding == UTFEncoding.UTF_16) { swapByteOrder(cast(wchar[])array); }
|
||||
else if(result.encoding == UTFEncoding.UTF_32) { swapByteOrder(cast(dchar[])array); }
|
||||
if (result.encoding == UTFEncoding.UTF_16)
|
||||
swapByteOrder(cast(wchar[])array);
|
||||
else if (result.encoding == UTFEncoding.UTF_32)
|
||||
swapByteOrder(cast(dchar[])array);
|
||||
}
|
||||
|
||||
result.array = array;
|
||||
return result;
|
||||
}
|
||||
///
|
||||
@safe unittest
|
||||
{
|
||||
{
|
||||
ubyte[] s = [0xEF, 0xBB, 0xBF, 'a'];
|
||||
FixUTFByteOrderResult r = fixUTFByteOrder(s);
|
||||
assert(r.encoding == UTFEncoding.UTF_8);
|
||||
assert(r.array.length == 1);
|
||||
assert(r.array == ['a']);
|
||||
assert(r.endian == Endian.littleEndian);
|
||||
}
|
||||
|
||||
{
|
||||
ubyte[] s = ['a'];
|
||||
FixUTFByteOrderResult r = fixUTFByteOrder(s);
|
||||
assert(r.encoding == UTFEncoding.UTF_8);
|
||||
assert(r.array.length == 1);
|
||||
assert(r.array == ['a']);
|
||||
assert(r.endian == Endian.bigEndian);
|
||||
}
|
||||
|
||||
{
|
||||
// strip 'a' b/c not complete unit
|
||||
ubyte[] s = [0xFE, 0xFF, 'a'];
|
||||
FixUTFByteOrderResult r = fixUTFByteOrder(s);
|
||||
assert(r.encoding == UTFEncoding.UTF_16);
|
||||
assert(r.array.length == 0);
|
||||
assert(r.endian == Endian.bigEndian);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue