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