mercurial/mpatch.c
changeset 1722 681c5c211b92
parent 597 e530637ea060
child 1746 299c3e26ee45
equal deleted inserted replaced
1721:801756d0ca84 1722:681c5c211b92
    41 #include <sys/types.h>
    41 #include <sys/types.h>
    42 #include <arpa/inet.h>
    42 #include <arpa/inet.h>
    43 #endif
    43 #endif
    44 
    44 
    45 static char mpatch_doc[] = "Efficient binary patching.";
    45 static char mpatch_doc[] = "Efficient binary patching.";
       
    46 static PyObject *mpatch_Error;
    46 
    47 
    47 struct frag {
    48 struct frag {
    48 	int start, end, len;
    49 	int start, end, len;
    49 	char *data;
    50 	char *data;
    50 };
    51 };
    63 		if (!a->base) {
    64 		if (!a->base) {
    64 			free(a);
    65 			free(a);
    65 			a = NULL;
    66 			a = NULL;
    66 		} else
    67 		} else
    67 			a->head = a->tail = a->base;
    68 			a->head = a->tail = a->base;
    68 	}
    69 			return a;
    69 	return a;
    70 	}
       
    71 	if (!PyErr_Occurred())
       
    72 		PyErr_NoMemory();
       
    73 	return NULL;
    70 }
    74 }
    71 
    75 
    72 static void lfree(struct flist *a)
    76 static void lfree(struct flist *a)
    73 {
    77 {
    74 	if (a) {
    78 	if (a) {
   213 	char *end = bin + len;
   217 	char *end = bin + len;
   214 	char decode[12]; /* for dealing with alignment issues */
   218 	char decode[12]; /* for dealing with alignment issues */
   215 
   219 
   216 	/* assume worst case size, we won't have many of these lists */
   220 	/* assume worst case size, we won't have many of these lists */
   217 	l = lalloc(len / 12);
   221 	l = lalloc(len / 12);
       
   222 	if (!l)
       
   223 		return NULL;
       
   224 
   218 	lt = l->tail;
   225 	lt = l->tail;
   219 
   226 
   220 	while (bin < end) {
   227 	while (bin < end) {
   221 		memcpy(decode, bin, 12);
   228 		memcpy(decode, bin, 12);
   222 		lt->start = ntohl(*(uint32_t *)decode);
   229 		lt->start = ntohl(*(uint32_t *)decode);
   225 		lt->data = bin + 12;
   232 		lt->data = bin + 12;
   226 		bin += 12 + lt->len;
   233 		bin += 12 + lt->len;
   227 		lt++;
   234 		lt++;
   228 	}
   235 	}
   229 
   236 
       
   237 	if (bin != end) {
       
   238 		if (!PyErr_Occurred())
       
   239 			PyErr_SetString(mpatch_Error, "patch cannot be decoded");
       
   240 		lfree(l);
       
   241 		return NULL;
       
   242 	}
       
   243 
   230 	l->tail = lt;
   244 	l->tail = lt;
   231 	return l;
   245 	return l;
   232 }
   246 }
   233 
   247 
   234 /* calculate the size of resultant text */
   248 /* calculate the size of resultant text */
   236 {
   250 {
   237 	int outlen = 0, last = 0;
   251 	int outlen = 0, last = 0;
   238 	struct frag *f = l->head;
   252 	struct frag *f = l->head;
   239 
   253 
   240 	while (f != l->tail) {
   254 	while (f != l->tail) {
       
   255 		if (f->start < last || f->end > len) {
       
   256 			if (!PyErr_Occurred())
       
   257 				PyErr_SetString(mpatch_Error,
       
   258 				                "invalid patch");
       
   259 			return -1;
       
   260 		}
   241 		outlen += f->start - last;
   261 		outlen += f->start - last;
   242 		last = f->end;
   262 		last = f->end;
   243 		outlen += f->len;
   263 		outlen += f->len;
   244 		f++;
   264 		f++;
   245 	}
   265 	}
   246 
   266 
   247 	outlen += len - last;
   267 	outlen += len - last;
   248 	return outlen;
   268 	return outlen;
   249 }
   269 }
   250 
   270 
   251 static void apply(char *buf, char *orig, int len, struct flist *l)
   271 static int apply(char *buf, char *orig, int len, struct flist *l)
   252 {
   272 {
   253 	struct frag *f = l->head;
   273 	struct frag *f = l->head;
   254 	int last = 0;
   274 	int last = 0;
   255 	char *p = buf;
   275 	char *p = buf;
   256 
   276 
   257 	while (f != l->tail) {
   277 	while (f != l->tail) {
       
   278 		if (f->start < last || f->end > len) {
       
   279 			if (!PyErr_Occurred())
       
   280 				PyErr_SetString(mpatch_Error,
       
   281 				                "invalid patch");
       
   282 			return 0;
       
   283 		}
   258 		memcpy(p, orig + last, f->start - last);
   284 		memcpy(p, orig + last, f->start - last);
   259 		p += f->start - last;
   285 		p += f->start - last;
   260 		memcpy(p, f->data, f->len);
   286 		memcpy(p, f->data, f->len);
   261 		last = f->end;
   287 		last = f->end;
   262 		p += f->len;
   288 		p += f->len;
   263 		f++;
   289 		f++;
   264 	}
   290 	}
   265 	memcpy(p, orig + last, len - last);
   291 	memcpy(p, orig + last, len - last);
       
   292 	return 1;
   266 }
   293 }
   267 
   294 
   268 /* recursively generate a patch of all bins between start and end */
   295 /* recursively generate a patch of all bins between start and end */
   269 static struct flist *fold(PyObject *bins, int start, int end)
   296 static struct flist *fold(PyObject *bins, int start, int end)
   270 {
   297 {
   302 		return text;
   329 		return text;
   303 	}
   330 	}
   304 
   331 
   305 	patch = fold(bins, 0, len);
   332 	patch = fold(bins, 0, len);
   306 	if (!patch)
   333 	if (!patch)
   307 		return PyErr_NoMemory();
   334 		return NULL;
   308 
   335 
   309 	outlen = calcsize(PyString_Size(text), patch);
   336 	outlen = calcsize(PyString_Size(text), patch);
       
   337 	if (outlen < 0) {
       
   338 		result = NULL;
       
   339 		goto cleanup;
       
   340 	}
   310 	result = PyString_FromStringAndSize(NULL, outlen);
   341 	result = PyString_FromStringAndSize(NULL, outlen);
   311 	if (result) {
   342 	if (!result) {
   312 		in = PyString_AsString(text);
   343 		result = NULL;
   313 		out = PyString_AsString(result);
   344 		goto cleanup;
   314 		apply(out, in, PyString_Size(text), patch);
   345 	}
   315 	}
   346 	in = PyString_AsString(text);
   316 
   347 	out = PyString_AsString(result);
       
   348 	if (!apply(out, in, PyString_Size(text), patch)) {
       
   349 		Py_DECREF(result);
       
   350 		result = NULL;
       
   351 	}
       
   352 cleanup:
   317 	lfree(patch);
   353 	lfree(patch);
   318 	return result;
   354 	return result;
   319 }
   355 }
   320 
   356 
   321 static PyMethodDef methods[] = {
   357 static PyMethodDef methods[] = {
   325 
   361 
   326 PyMODINIT_FUNC
   362 PyMODINIT_FUNC
   327 initmpatch(void)
   363 initmpatch(void)
   328 {
   364 {
   329 	Py_InitModule3("mpatch", methods, mpatch_doc);
   365 	Py_InitModule3("mpatch", methods, mpatch_doc);
   330 }
   366 	mpatch_Error = PyErr_NewException("mpatch.mpatchError", NULL, NULL);
   331 
   367 }
       
   368