##// END OF EJS Templates
patches: move assignment outside the conditional...
Boris Feld -
r35959:3028a321 default
parent child Browse files
Show More
@@ -1,200 +1,201 b''
1 /*
1 /*
2 mpatch.c - efficient binary patching for Mercurial
2 mpatch.c - efficient binary patching for Mercurial
3
3
4 This implements a patch algorithm that's O(m + nlog n) where m is the
4 This implements a patch algorithm that's O(m + nlog n) where m is the
5 size of the output and n is the number of patches.
5 size of the output and n is the number of patches.
6
6
7 Given a list of binary patches, it unpacks each into a hunk list,
7 Given a list of binary patches, it unpacks each into a hunk list,
8 then combines the hunk lists with a treewise recursion to form a
8 then combines the hunk lists with a treewise recursion to form a
9 single hunk list. This hunk list is then applied to the original
9 single hunk list. This hunk list is then applied to the original
10 text.
10 text.
11
11
12 The text (or binary) fragments are copied directly from their source
12 The text (or binary) fragments are copied directly from their source
13 Python objects into a preallocated output string to avoid the
13 Python objects into a preallocated output string to avoid the
14 allocation of intermediate Python objects. Working memory is about 2x
14 allocation of intermediate Python objects. Working memory is about 2x
15 the total number of hunks.
15 the total number of hunks.
16
16
17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
18
18
19 This software may be used and distributed according to the terms
19 This software may be used and distributed according to the terms
20 of the GNU General Public License, incorporated herein by reference.
20 of the GNU General Public License, incorporated herein by reference.
21 */
21 */
22
22
23 #define PY_SSIZE_T_CLEAN
23 #define PY_SSIZE_T_CLEAN
24 #include <Python.h>
24 #include <Python.h>
25 #include <stdlib.h>
25 #include <stdlib.h>
26 #include <string.h>
26 #include <string.h>
27
27
28 #include "bitmanipulation.h"
28 #include "bitmanipulation.h"
29 #include "compat.h"
29 #include "compat.h"
30 #include "mpatch.h"
30 #include "mpatch.h"
31 #include "util.h"
31 #include "util.h"
32
32
33 static char mpatch_doc[] = "Efficient binary patching.";
33 static char mpatch_doc[] = "Efficient binary patching.";
34 static PyObject *mpatch_Error;
34 static PyObject *mpatch_Error;
35
35
36 static void setpyerr(int r)
36 static void setpyerr(int r)
37 {
37 {
38 switch (r) {
38 switch (r) {
39 case MPATCH_ERR_NO_MEM:
39 case MPATCH_ERR_NO_MEM:
40 PyErr_NoMemory();
40 PyErr_NoMemory();
41 break;
41 break;
42 case MPATCH_ERR_CANNOT_BE_DECODED:
42 case MPATCH_ERR_CANNOT_BE_DECODED:
43 PyErr_SetString(mpatch_Error, "patch cannot be decoded");
43 PyErr_SetString(mpatch_Error, "patch cannot be decoded");
44 break;
44 break;
45 case MPATCH_ERR_INVALID_PATCH:
45 case MPATCH_ERR_INVALID_PATCH:
46 PyErr_SetString(mpatch_Error, "invalid patch");
46 PyErr_SetString(mpatch_Error, "invalid patch");
47 break;
47 break;
48 }
48 }
49 }
49 }
50
50
51 struct mpatch_flist *cpygetitem(void *bins, ssize_t pos)
51 struct mpatch_flist *cpygetitem(void *bins, ssize_t pos)
52 {
52 {
53 const char *buffer;
53 const char *buffer;
54 struct mpatch_flist *res;
54 struct mpatch_flist *res;
55 ssize_t blen;
55 ssize_t blen;
56 int r;
56 int r;
57
57
58 PyObject *tmp = PyList_GetItem((PyObject*)bins, pos);
58 PyObject *tmp = PyList_GetItem((PyObject*)bins, pos);
59 if (!tmp)
59 if (!tmp)
60 return NULL;
60 return NULL;
61 if (PyObject_AsCharBuffer(tmp, &buffer, (Py_ssize_t*)&blen))
61 if (PyObject_AsCharBuffer(tmp, &buffer, (Py_ssize_t*)&blen))
62 return NULL;
62 return NULL;
63 if ((r = mpatch_decode(buffer, blen, &res)) < 0) {
63 if ((r = mpatch_decode(buffer, blen, &res)) < 0) {
64 if (!PyErr_Occurred())
64 if (!PyErr_Occurred())
65 setpyerr(r);
65 setpyerr(r);
66 return NULL;
66 return NULL;
67 }
67 }
68 return res;
68 return res;
69 }
69 }
70
70
71 static PyObject *
71 static PyObject *
72 patches(PyObject *self, PyObject *args)
72 patches(PyObject *self, PyObject *args)
73 {
73 {
74 PyObject *text, *bins, *result;
74 PyObject *text, *bins, *result;
75 struct mpatch_flist *patch;
75 struct mpatch_flist *patch;
76 const char *in;
76 const char *in;
77 int r = 0;
77 int r = 0;
78 char *out;
78 char *out;
79 Py_ssize_t len, outlen, inlen;
79 Py_ssize_t len, outlen, inlen;
80
80
81 if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins))
81 if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins))
82 return NULL;
82 return NULL;
83
83
84 len = PyList_Size(bins);
84 len = PyList_Size(bins);
85 if (!len) {
85 if (!len) {
86 /* nothing to do */
86 /* nothing to do */
87 Py_INCREF(text);
87 Py_INCREF(text);
88 return text;
88 return text;
89 }
89 }
90
90
91 if (PyObject_AsCharBuffer(text, &in, &inlen))
91 if (PyObject_AsCharBuffer(text, &in, &inlen))
92 return NULL;
92 return NULL;
93
93
94 patch = mpatch_fold(bins, cpygetitem, 0, len);
94 patch = mpatch_fold(bins, cpygetitem, 0, len);
95 if (!patch) { /* error already set or memory error */
95 if (!patch) { /* error already set or memory error */
96 if (!PyErr_Occurred())
96 if (!PyErr_Occurred())
97 PyErr_NoMemory();
97 PyErr_NoMemory();
98 return NULL;
98 return NULL;
99 }
99 }
100
100
101 outlen = mpatch_calcsize(inlen, patch);
101 outlen = mpatch_calcsize(inlen, patch);
102 if (outlen < 0) {
102 if (outlen < 0) {
103 r = (int)outlen;
103 r = (int)outlen;
104 result = NULL;
104 result = NULL;
105 goto cleanup;
105 goto cleanup;
106 }
106 }
107 result = PyBytes_FromStringAndSize(NULL, outlen);
107 result = PyBytes_FromStringAndSize(NULL, outlen);
108 if (!result) {
108 if (!result) {
109 result = NULL;
109 result = NULL;
110 goto cleanup;
110 goto cleanup;
111 }
111 }
112 out = PyBytes_AsString(result);
112 out = PyBytes_AsString(result);
113 if ((r = mpatch_apply(out, in, inlen, patch)) < 0) {
113 r = mpatch_apply(out, in, inlen, patch);
114 if (r < 0) {
114 Py_DECREF(result);
115 Py_DECREF(result);
115 result = NULL;
116 result = NULL;
116 }
117 }
117 cleanup:
118 cleanup:
118 mpatch_lfree(patch);
119 mpatch_lfree(patch);
119 if (!result && !PyErr_Occurred())
120 if (!result && !PyErr_Occurred())
120 setpyerr(r);
121 setpyerr(r);
121 return result;
122 return result;
122 }
123 }
123
124
124 /* calculate size of a patched file directly */
125 /* calculate size of a patched file directly */
125 static PyObject *
126 static PyObject *
126 patchedsize(PyObject *self, PyObject *args)
127 patchedsize(PyObject *self, PyObject *args)
127 {
128 {
128 long orig, start, end, len, outlen = 0, last = 0, pos = 0;
129 long orig, start, end, len, outlen = 0, last = 0, pos = 0;
129 Py_ssize_t patchlen;
130 Py_ssize_t patchlen;
130 char *bin;
131 char *bin;
131
132
132 if (!PyArg_ParseTuple(args, "ls#", &orig, &bin, &patchlen))
133 if (!PyArg_ParseTuple(args, "ls#", &orig, &bin, &patchlen))
133 return NULL;
134 return NULL;
134
135
135 while (pos >= 0 && pos < patchlen) {
136 while (pos >= 0 && pos < patchlen) {
136 start = getbe32(bin + pos);
137 start = getbe32(bin + pos);
137 end = getbe32(bin + pos + 4);
138 end = getbe32(bin + pos + 4);
138 len = getbe32(bin + pos + 8);
139 len = getbe32(bin + pos + 8);
139 if (start > end)
140 if (start > end)
140 break; /* sanity check */
141 break; /* sanity check */
141 pos += 12 + len;
142 pos += 12 + len;
142 outlen += start - last;
143 outlen += start - last;
143 last = end;
144 last = end;
144 outlen += len;
145 outlen += len;
145 }
146 }
146
147
147 if (pos != patchlen) {
148 if (pos != patchlen) {
148 if (!PyErr_Occurred())
149 if (!PyErr_Occurred())
149 PyErr_SetString(mpatch_Error, "patch cannot be decoded");
150 PyErr_SetString(mpatch_Error, "patch cannot be decoded");
150 return NULL;
151 return NULL;
151 }
152 }
152
153
153 outlen += orig - last;
154 outlen += orig - last;
154 return Py_BuildValue("l", outlen);
155 return Py_BuildValue("l", outlen);
155 }
156 }
156
157
157 static PyMethodDef methods[] = {
158 static PyMethodDef methods[] = {
158 {"patches", patches, METH_VARARGS, "apply a series of patches\n"},
159 {"patches", patches, METH_VARARGS, "apply a series of patches\n"},
159 {"patchedsize", patchedsize, METH_VARARGS, "calculed patched size\n"},
160 {"patchedsize", patchedsize, METH_VARARGS, "calculed patched size\n"},
160 {NULL, NULL}
161 {NULL, NULL}
161 };
162 };
162
163
163 static const int version = 1;
164 static const int version = 1;
164
165
165 #ifdef IS_PY3K
166 #ifdef IS_PY3K
166 static struct PyModuleDef mpatch_module = {
167 static struct PyModuleDef mpatch_module = {
167 PyModuleDef_HEAD_INIT,
168 PyModuleDef_HEAD_INIT,
168 "mpatch",
169 "mpatch",
169 mpatch_doc,
170 mpatch_doc,
170 -1,
171 -1,
171 methods
172 methods
172 };
173 };
173
174
174 PyMODINIT_FUNC PyInit_mpatch(void)
175 PyMODINIT_FUNC PyInit_mpatch(void)
175 {
176 {
176 PyObject *m;
177 PyObject *m;
177
178
178 m = PyModule_Create(&mpatch_module);
179 m = PyModule_Create(&mpatch_module);
179 if (m == NULL)
180 if (m == NULL)
180 return NULL;
181 return NULL;
181
182
182 mpatch_Error = PyErr_NewException("mercurial.cext.mpatch.mpatchError",
183 mpatch_Error = PyErr_NewException("mercurial.cext.mpatch.mpatchError",
183 NULL, NULL);
184 NULL, NULL);
184 Py_INCREF(mpatch_Error);
185 Py_INCREF(mpatch_Error);
185 PyModule_AddObject(m, "mpatchError", mpatch_Error);
186 PyModule_AddObject(m, "mpatchError", mpatch_Error);
186 PyModule_AddIntConstant(m, "version", version);
187 PyModule_AddIntConstant(m, "version", version);
187
188
188 return m;
189 return m;
189 }
190 }
190 #else
191 #else
191 PyMODINIT_FUNC
192 PyMODINIT_FUNC
192 initmpatch(void)
193 initmpatch(void)
193 {
194 {
194 PyObject *m;
195 PyObject *m;
195 m = Py_InitModule3("mpatch", methods, mpatch_doc);
196 m = Py_InitModule3("mpatch", methods, mpatch_doc);
196 mpatch_Error = PyErr_NewException("mercurial.cext.mpatch.mpatchError",
197 mpatch_Error = PyErr_NewException("mercurial.cext.mpatch.mpatchError",
197 NULL, NULL);
198 NULL, NULL);
198 PyModule_AddIntConstant(m, "version", version);
199 PyModule_AddIntConstant(m, "version", version);
199 }
200 }
200 #endif
201 #endif
General Comments 0
You need to be logged in to leave comments. Login now