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}