1 module compy.common; 2 3 import compy.hal; 4 import compy.nintendo; 5 6 import std.algorithm; 7 import std.format; 8 9 ulong parseOffset(string arg) { 10 ulong offset; 11 if ((arg.length > 1) && (arg[1] == 'x')) { 12 formattedRead(arg, "0x%x", &offset); 13 } else { 14 formattedRead(arg, "%s", &offset); 15 } 16 return offset; 17 } 18 19 enum Format { 20 HALLZ1, 21 HALLZ2, 22 NintendoLZ1, 23 NintendoLZ2 24 } 25 26 ubyte[] decomp(Format format, const ubyte[] input) @safe { 27 size_t unused; 28 return decomp(format, input, unused); 29 } 30 ubyte[] decomp(Format format, const ubyte[] input, out size_t compressedSize) @safe { 31 final switch (format) { 32 case Format.HALLZ1: return HALLZ1.decomp(input, compressedSize); 33 case Format.HALLZ2: return HALLZ2.decomp(input, compressedSize); 34 case Format.NintendoLZ1: return NintendoLZ1.decomp(input, compressedSize); 35 case Format.NintendoLZ2: return NintendoLZ2.decomp(input, compressedSize); 36 } 37 } 38 39 ubyte[] comp(Format format, const ubyte[] input) @safe { 40 final switch (format) { 41 case Format.HALLZ1: return HALLZ1.comp(input); 42 case Format.HALLZ2: return HALLZ2.comp(input); 43 case Format.NintendoLZ1: return NintendoLZ1.comp(input); 44 case Format.NintendoLZ2: return NintendoLZ2.comp(input); 45 } 46 } 47 48 package: 49 50 ubyte readByte(T)(ref T file) { 51 import std.range : front, popFront; 52 auto v = file.front; 53 file.popFront(); 54 return v; 55 } 56 57 ubyte[] uncompdata(const ubyte[] input, out ushort size) @safe { 58 size = cast(ushort)min(input.length,1024); 59 return buildCommand(0, size, input[0..size]); 60 } 61 62 const(ubyte)[] increaseval(ubyte input, in int length) pure nothrow @safe { 63 ubyte[] output = new ubyte[](length); 64 foreach(ref val; output) 65 val = input++; 66 return output; 67 } 68 unittest { 69 assert((0).increaseval(1) == [0], "Increaseval: First value unaltered"); 70 assert((0).increaseval(3) == [0, 1, 2], "Increaseval: algorithm"); 71 assert((255).increaseval(3) == [255, 0, 1], "Increaseval: Wrapping values"); 72 assert((0).increaseval(0) == [], "Increaseval: Void"); 73 } 74 ubyte reversebits(ubyte input) @safe pure nothrow @nogc { 75 ubyte val = input; 76 val = ((val >> 1) & 0x55) | ((val << 1) & 0xAA); 77 val = ((val >> 2) & 0x33) | ((val << 2) & 0xCC); 78 val = ((val >> 4) & 0x0F) | ((val << 4) & 0xF0); 79 return val; 80 } 81 ushort reversebits(ushort input) @safe pure nothrow @nogc { 82 ushort val = input; 83 val = ((val & 0x5555) << 1) | ((val & 0xAAAA) >> 1); 84 val = ((val & 0x3333) << 2) | ((val & 0xCCCC) >> 2); 85 val = ((val & 0x0F0F) << 4) | ((val & 0xF0F0) >> 4); 86 val = ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8); 87 return val; 88 } 89 uint reversebits(uint input) @safe pure nothrow @nogc { 90 uint val = input; 91 val = ((val & 0x55555555) << 1) | ((val & 0xAAAAAAAA) >> 1); 92 val = ((val & 0x33333333) << 2) | ((val & 0xCCCCCCCC) >> 2); 93 val = ((val & 0x0F0F0F0F) << 4) | ((val & 0xF0F0F0F0) >> 4); 94 val = ((val & 0x00FF00FF) << 8) | ((val & 0xFF00FF00) >> 8); 95 val = ((val & 0x0000FFFF) << 16) | ((val & 0xFFFF0000) >> 16); 96 return val; 97 } 98 pure nothrow @nogc @safe unittest { 99 assert(cast(ubyte)1.reversebits == cast(ubyte)128, "Bit reversal: algorithm"); 100 assert(cast(uint)0x80000000.reversebits == 1, "Bit reversal: int"); 101 } 102 ubyte[] repeatByte(const ubyte[] input, const ubyte[] buffer, out ushort size) @safe pure nothrow { 103 ubyte match = input[0]; 104 foreach (val; input) { 105 if ((val != match) || (size == 1024)) 106 break; 107 size++; 108 } 109 return buildCommand(1, size, match); 110 } 111 ubyte[] repeatWord(const ubyte[] input, const ubyte[] buffer, out ushort size) @safe pure nothrow { 112 if (input.length < 2) 113 return []; 114 const(ubyte)[] match = input[0..2]; 115 foreach (k, val; input) { 116 if ((val != match[k%2]) || (size == 1024)) 117 break; 118 if (k%2 == 1) 119 size++; 120 } 121 size *= 2; 122 return buildCommand(2,size/2, match); 123 } 124 ubyte[] incByteFill(const ubyte[] input, const ubyte[] buffer, out ushort size) @safe pure nothrow { 125 ubyte initialVal, tmpVal; 126 initialVal = tmpVal = input[0]; 127 size = 1; 128 foreach (k, val; input[1..$]) { 129 if (++tmpVal != val) 130 break; 131 size++; 132 } 133 return buildCommand(3,size,initialVal); 134 } 135 ubyte[] zeroFill(const ubyte[] input, const ubyte[] buffer, out ushort size) @safe pure nothrow { 136 size = 0; 137 foreach (k, val; input[1..$]) { 138 if (val != 0) { 139 break; 140 } 141 size++; 142 } 143 return buildCommand(3, size, []); 144 } 145 ubyte[] bufferCopy(const ubyte[] input, const ubyte[] buffer, out ushort size) @safe pure nothrow { 146 import std.range : empty; 147 if (input.empty || buffer.empty) 148 return []; 149 size = cast(ushort)min(input.length, 1024); 150 long tmp = -1; 151 while ((tmp == -1) && (size > 0)) { 152 tmp = countUntil(buffer, input[0..size--]); 153 } 154 return buildCommand(4, size, cast(ushort)tmp); 155 } 156 ubyte[] bufferCopyBigEndian(const ubyte[] input, const ubyte[] buffer, out ushort size) @safe pure nothrow { 157 import std.range : empty; 158 if (input.empty || buffer.empty) 159 return []; 160 size = cast(ushort)min(input.length, 1024); 161 long tmp = -1; 162 while ((tmp == -1) && (size > 0)) { 163 tmp = countUntil(buffer, input[0..size--]); 164 } 165 return buildCommandBE(4, size, cast(ushort)tmp); 166 } 167 ubyte[] bitReverseBufferCopy(const ubyte[] input, const ubyte[] buffer, out ushort size) @safe pure nothrow { 168 return buildCommand(5, 0, []); 169 } 170 ubyte[] byteReverseBufferCopy(const ubyte[] input, const ubyte[] buffer, out ushort size) @safe pure nothrow { 171 return buildCommand(6, 0, []); 172 } 173 ubyte[] buildCommand(ubyte ID, ushort length, ubyte payLoad) @safe pure nothrow { 174 return buildCommand(ID,length,[payLoad]); 175 } 176 ubyte[] buildCommand(ubyte ID, ushort length, ushort payLoad) @safe pure nothrow { 177 return buildCommand(ID,length,[payLoad&0xFF, payLoad>>8]); 178 } 179 ubyte[] buildCommandBE(ubyte ID, ushort length, ushort payLoad) @safe pure nothrow { 180 return buildCommand(ID,length,[payLoad>>8, payLoad&0xFF]); 181 } 182 ubyte[] buildCommand(ubyte ID, ushort length, const ubyte[] payLoad) @safe pure nothrow { 183 ubyte[] output; 184 if (length == 0) { 185 return []; 186 } else if (length <= 32) { 187 output = new ubyte[payLoad.length+1]; 188 output[0] = cast(ubyte)((ID<<5) + ((length-1)&0x1F)); 189 } else { 190 output = new ubyte[payLoad.length+2]; 191 output[0] = cast(ubyte)(0xE0 + (ID<<2) + ((length-1)>>8)); 192 output[1] = (length-1)&0xFF; 193 } 194 output[$-payLoad.length..$] = payLoad; 195 return output; 196 }