all repos — mgba @ fa884d071ecaa3e05ff20b45a67bf9500dd3d6b6

mGBA Game Boy Advance Emulator

src/util/patch-fast.c (view raw)

  1/* Copyright (c) 2013-2016 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include <mgba-util/patch/fast.h>
  7
  8DEFINE_VECTOR(PatchFastExtents, struct PatchFastExtent);
  9
 10size_t _fastOutputSize(struct Patch* patch, size_t inSize);
 11bool _fastApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* out, size_t outSize);
 12
 13void initPatchFast(struct PatchFast* patch) {
 14	PatchFastExtentsInit(&patch->extents, 32);
 15	patch->d.outputSize = _fastOutputSize;
 16	patch->d.applyPatch = _fastApplyPatch;
 17}
 18
 19void deinitPatchFast(struct PatchFast* patch) {
 20	PatchFastExtentsDeinit(&patch->extents);
 21}
 22
 23bool diffPatchFast(struct PatchFast* patch, const void* restrict in, const void* restrict out, size_t size) {
 24	PatchFastExtentsClear(&patch->extents);
 25	const uint32_t* iptr = in;
 26	const uint32_t* optr = out;
 27	size_t extentOff = 0;
 28	struct PatchFastExtent* extent = NULL;
 29	size_t off;
 30	for (off = 0; off < (size & ~15); off += 16) {
 31		uint32_t a = iptr[0] ^ optr[0];
 32		uint32_t b = iptr[1] ^ optr[1];
 33		uint32_t c = iptr[2] ^ optr[2];
 34		uint32_t d = iptr[3] ^ optr[3];
 35		iptr += 4;
 36		optr += 4;
 37		if (a | b | c | d) {
 38			if (!extent) {
 39				extent = PatchFastExtentsAppend(&patch->extents);
 40				extent->offset = off;
 41				extentOff = 0;
 42			}
 43			extent->extent[extentOff] = a;
 44			extent->extent[extentOff + 1] = b;
 45			extent->extent[extentOff + 2] = c;
 46			extent->extent[extentOff + 3] = d;
 47			extentOff += 4;
 48			if (extentOff == PATCH_FAST_EXTENT) {
 49				extent->length = extentOff * 4;
 50				extent = NULL;
 51			}
 52		} else if (extent) {
 53			extent->length = extentOff * 4;
 54			extent = NULL;
 55		}
 56	}
 57	if (extent) {
 58		extent->length = extentOff * 4;
 59		extent = NULL;
 60	}
 61	const uint32_t* iptr8 = iptr;
 62	const uint32_t* optr8 = optr;
 63	for (; off < size; ++off) {
 64		uint8_t a = iptr8[0] ^ optr8[0];
 65		++iptr8;
 66		++optr8;
 67		if (a) {
 68			if (!extent) {
 69				extent = PatchFastExtentsAppend(&patch->extents);
 70				extent->offset = off;
 71			}
 72			((uint8_t*) extent->extent)[extentOff] = a;
 73			++extentOff;
 74		} else if (extent) {
 75			extent->length = extentOff;
 76			extent = NULL;
 77		}
 78	}
 79	if (extent) {
 80		extent->length = extentOff;
 81		extent = NULL;
 82	}
 83
 84	return true;
 85}
 86
 87size_t _fastOutputSize(struct Patch* patch, size_t inSize) {
 88	UNUSED(patch);
 89	return inSize;
 90}
 91
 92bool _fastApplyPatch(struct Patch* p, const void* in, size_t inSize, void* out, size_t outSize) {
 93	struct PatchFast* patch = (struct PatchFast*) p;
 94	if (inSize != outSize) {
 95		return false;
 96	}
 97	const uint32_t* iptr = in;
 98	uint32_t* optr = out;
 99	size_t lastWritten = 0;
100	size_t s;
101	for (s = 0; s < PatchFastExtentsSize(&patch->extents); ++s) {
102		struct PatchFastExtent* extent = PatchFastExtentsGetPointer(&patch->extents, s);
103		if (extent->length + extent->offset > outSize) {
104			return false;
105		}
106		memcpy(optr, iptr, extent->offset - lastWritten);
107		optr = (uint32_t*) out + extent->offset / 4;
108		iptr = (uint32_t*) in + extent->offset / 4;
109		uint32_t* eptr = extent->extent;
110		size_t off;
111		for (off = 0; off < (extent->length & ~15); off += 16) {
112			optr[0] = iptr[0] ^ eptr[0];
113			optr[1] = iptr[1] ^ eptr[1];
114			optr[2] = iptr[2] ^ eptr[2];
115			optr[3] = iptr[3] ^ eptr[3];
116			optr += 4;
117			iptr += 4;
118			eptr += 4;
119		}
120		for (; off < extent->length; ++off) {
121			*(uint8_t*) optr = *(uint8_t*) iptr ^ *(uint8_t*) eptr;
122			++optr;
123			++iptr;
124			++eptr;
125		}
126		lastWritten = extent->offset + off;
127	}
128	memcpy(optr, iptr, outSize - lastWritten);
129	return true;
130}