mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	refactor unpack, add unpack_from
This commit is contained in:
		
							parent
							
								
									d5e0dc51cf
								
							
						
					
					
						commit
						eb62127842
					
				
					 3 changed files with 168 additions and 69 deletions
				
			
		|  | @ -73,3 +73,15 @@ def unpack(fmt, s): | ||||||
|     except KeyError: |     except KeyError: | ||||||
|         o = _compile(fmt) |         o = _compile(fmt) | ||||||
|     return o.unpack(s) |     return o.unpack(s) | ||||||
|  |      | ||||||
|  | def unpack_from(fmt, buf, offset=0): | ||||||
|  |     """ | ||||||
|  |     Unpack the buffer, containing packed C structure data, according to | ||||||
|  |     fmt starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt). | ||||||
|  |     See struct.__doc__ for more on format strings. | ||||||
|  |     """ | ||||||
|  |     try: | ||||||
|  |         o = _cache[fmt] | ||||||
|  |     except KeyError: | ||||||
|  |         o = _compile(fmt) | ||||||
|  |     return o.unpack_from(buf, offset) | ||||||
|  | @ -437,3 +437,44 @@ def test_705836(): | ||||||
|         TestFailed("expected OverflowError") |         TestFailed("expected OverflowError") | ||||||
| 
 | 
 | ||||||
| test_705836() | test_705836() | ||||||
|  | 
 | ||||||
|  | def test_unpack_from(): | ||||||
|  |     test_string = 'abcd01234' | ||||||
|  |     fmt = '4s' | ||||||
|  |     s = struct.Struct(fmt) | ||||||
|  |     for cls in (str, buffer): | ||||||
|  |         data = cls(test_string) | ||||||
|  |         assert s.unpack_from(data) == ('abcd',) | ||||||
|  |         assert s.unpack_from(data, 2) == ('cd01',) | ||||||
|  |         assert s.unpack_from(data, 4) == ('0123',) | ||||||
|  |         for i in xrange(6): | ||||||
|  |             assert s.unpack_from(data, i) == (data[i:i+4],) | ||||||
|  |         for i in xrange(6, len(test_string) + 1): | ||||||
|  |             simple_err(s.unpack_from, data, i) | ||||||
|  |     for cls in (str, buffer): | ||||||
|  |         data = cls(test_string) | ||||||
|  |         assert struct.unpack_from(fmt, data) == ('abcd',) | ||||||
|  |         assert struct.unpack_from(fmt, data, 2) == ('cd01',) | ||||||
|  |         assert struct.unpack_from(fmt, data, 4) == ('0123',) | ||||||
|  |         for i in xrange(6): | ||||||
|  |             assert struct.unpack_from(fmt, data, i) == (data[i:i+4],) | ||||||
|  |         for i in xrange(6, len(test_string) + 1): | ||||||
|  |             simple_err(struct.unpack_from, fmt, data, i) | ||||||
|  | 
 | ||||||
|  | test_unpack_from() | ||||||
|  | 
 | ||||||
|  | def test_1229380(): | ||||||
|  |     for endian in ('', '>', '<'): | ||||||
|  |         for cls in (int, long): | ||||||
|  |             for fmt in ('B', 'H', 'I', 'L'): | ||||||
|  |                 any_err(struct.pack, endian + fmt, cls(-1)) | ||||||
|  | 
 | ||||||
|  |             any_err(struct.pack, endian + 'B', cls(300)) | ||||||
|  |             any_err(struct.pack, endian + 'H', cls(70000)) | ||||||
|  | 
 | ||||||
|  |         any_err(struct.pack, endian + 'I', sys.maxint * 4L) | ||||||
|  |         any_err(struct.pack, endian + 'L', sys.maxint * 4L) | ||||||
|  | 
 | ||||||
|  | if 0: | ||||||
|  |     # TODO: bug #1229380 | ||||||
|  |     test_1229380() | ||||||
|  |  | ||||||
|  | @ -32,7 +32,7 @@ typedef struct _formatdef { | ||||||
| typedef struct _formatcode { | typedef struct _formatcode { | ||||||
| 	const struct _formatdef *fmtdef; | 	const struct _formatdef *fmtdef; | ||||||
| 	int offset; | 	int offset; | ||||||
| 	int repeat; | 	int size; | ||||||
| } formatcode; | } formatcode; | ||||||
| 
 | 
 | ||||||
| /* Struct object interface */ | /* Struct object interface */ | ||||||
|  | @ -46,6 +46,7 @@ typedef struct { | ||||||
| 	PyObject *weakreflist; /* List of weak references */ | 	PyObject *weakreflist; /* List of weak references */ | ||||||
| } PyStructObject; | } PyStructObject; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| #define PyStruct_Check(op) PyObject_TypeCheck(op, &PyStructType) | #define PyStruct_Check(op) PyObject_TypeCheck(op, &PyStructType) | ||||||
| #define PyStruct_CheckExact(op) ((op)->ob_type == &PyStructType) | #define PyStruct_CheckExact(op) ((op)->ob_type == &PyStructType) | ||||||
| 
 | 
 | ||||||
|  | @ -962,7 +963,7 @@ prepare_s(PyStructObject *self) | ||||||
| 	const char *s; | 	const char *s; | ||||||
| 	const char *fmt; | 	const char *fmt; | ||||||
| 	char c; | 	char c; | ||||||
| 	int size, len, numcodes, num, itemsize, x; | 	int size, len, num, itemsize, x; | ||||||
| 
 | 
 | ||||||
| 	fmt = PyString_AS_STRING(self->s_format); | 	fmt = PyString_AS_STRING(self->s_format); | ||||||
| 
 | 
 | ||||||
|  | @ -971,7 +972,6 @@ prepare_s(PyStructObject *self) | ||||||
| 	s = fmt; | 	s = fmt; | ||||||
| 	size = 0; | 	size = 0; | ||||||
| 	len = 0; | 	len = 0; | ||||||
| 	numcodes = 0; |  | ||||||
| 	while ((c = *s++) != '\0') { | 	while ((c = *s++) != '\0') { | ||||||
| 		if (isspace(Py_CHARMASK(c))) | 		if (isspace(Py_CHARMASK(c))) | ||||||
| 			continue; | 			continue; | ||||||
|  | @ -1003,7 +1003,6 @@ prepare_s(PyStructObject *self) | ||||||
| 			case 'x': break; | 			case 'x': break; | ||||||
| 			default: len += num; break; | 			default: len += num; break; | ||||||
| 		} | 		} | ||||||
| 		if (c != 'x') numcodes++; |  | ||||||
| 
 | 
 | ||||||
| 		itemsize = e->size; | 		itemsize = e->size; | ||||||
| 		size = align(size, c, e); | 		size = align(size, c, e); | ||||||
|  | @ -1018,7 +1017,7 @@ prepare_s(PyStructObject *self) | ||||||
| 
 | 
 | ||||||
| 	self->s_size = size; | 	self->s_size = size; | ||||||
| 	self->s_len = len; | 	self->s_len = len; | ||||||
| 	codes = PyMem_MALLOC((numcodes + 1) * sizeof(formatcode)); | 	codes = PyMem_MALLOC((len + 1) * sizeof(formatcode)); | ||||||
| 	if (codes == NULL) { | 	if (codes == NULL) { | ||||||
| 		PyErr_NoMemory(); | 		PyErr_NoMemory(); | ||||||
| 		return -1; | 		return -1; | ||||||
|  | @ -1043,17 +1042,27 @@ prepare_s(PyStructObject *self) | ||||||
| 		e = getentry(c, f); | 		e = getentry(c, f); | ||||||
| 		 | 		 | ||||||
| 		size = align(size, c, e); | 		size = align(size, c, e); | ||||||
| 		if (c != 'x') { | 		if (c == 's' || c == 'p') { | ||||||
| 			codes->offset = size; | 			codes->offset = size; | ||||||
| 			codes->repeat = num; | 			codes->size = num; | ||||||
| 			codes->fmtdef = e; | 			codes->fmtdef = e; | ||||||
| 			codes++; | 			codes++; | ||||||
|  | 			size += num; | ||||||
|  | 		} else if (c == 'x') { | ||||||
|  | 			size += num; | ||||||
|  | 		} else { | ||||||
|  | 			while (--num >= 0) { | ||||||
|  | 				codes->offset = size; | ||||||
|  | 				codes->size = e->size; | ||||||
|  | 				codes->fmtdef = e; | ||||||
|  | 				codes++; | ||||||
|  | 				size += e->size; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		size += num * e->size; |  | ||||||
| 	} | 	} | ||||||
| 	codes->fmtdef = NULL; | 	codes->fmtdef = NULL; | ||||||
| 	codes->offset = -1; | 	codes->offset = size; | ||||||
| 	codes->repeat = -1; | 	codes->size = 0; | ||||||
| 	 | 	 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -1111,6 +1120,46 @@ s_dealloc(PyStructObject *s) | ||||||
| 	s->ob_type->tp_free((PyObject *)s); | 	s->ob_type->tp_free((PyObject *)s); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static PyObject * | ||||||
|  | s_unpack_internal(PyStructObject *soself, char *startfrom) { | ||||||
|  | 	formatcode *code; | ||||||
|  | 	Py_ssize_t i = 0; | ||||||
|  | 	PyObject *result = PyTuple_New(soself->s_len); | ||||||
|  | 	if (result == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	for (code = soself->s_codes; code->fmtdef != NULL; code++) { | ||||||
|  | 		PyObject *v; | ||||||
|  | 		const formatdef *e = code->fmtdef; | ||||||
|  | 		const char *res = startfrom + code->offset; | ||||||
|  | 		if (e->format == 's') { | ||||||
|  | 			v = PyString_FromStringAndSize(res, code->size); | ||||||
|  | 			if (v == NULL) | ||||||
|  | 				goto fail; | ||||||
|  | 			PyTuple_SET_ITEM(result, i++, v); | ||||||
|  | 		} else if (e->format == 'p') { | ||||||
|  | 			Py_ssize_t n = *(unsigned char*)res; | ||||||
|  | 			if (n >= code->size) | ||||||
|  | 				n = code->size - 1; | ||||||
|  | 			v = PyString_FromStringAndSize(res + 1, n); | ||||||
|  | 			if (v == NULL) | ||||||
|  | 				goto fail; | ||||||
|  | 			PyTuple_SET_ITEM(result, i++, v); | ||||||
|  | 		} else { | ||||||
|  | 			v = e->unpack(res, e); | ||||||
|  | 			if (v == NULL) | ||||||
|  | 				goto fail; | ||||||
|  | 			PyTuple_SET_ITEM(result, i++, v); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return result; | ||||||
|  | fail: | ||||||
|  | 	Py_DECREF(result); | ||||||
|  | 	return NULL; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| PyDoc_STRVAR(s_unpack__doc__, | PyDoc_STRVAR(s_unpack__doc__, | ||||||
| "unpack(str) -> (v1, v2, ...)\n\
 | "unpack(str) -> (v1, v2, ...)\n\
 | ||||||
| \n\ | \n\ | ||||||
|  | @ -1121,63 +1170,62 @@ strings."); | ||||||
| static PyObject * | static PyObject * | ||||||
| s_unpack(PyObject *self, PyObject *inputstr) | s_unpack(PyObject *self, PyObject *inputstr) | ||||||
| { | { | ||||||
| 	PyStructObject *soself; | 	PyStructObject *soself = (PyStructObject *)self; | ||||||
| 	PyObject *result; |  | ||||||
| 	char *restart; |  | ||||||
| 	formatcode *code; |  | ||||||
| 	Py_ssize_t i; |  | ||||||
| 	 |  | ||||||
| 	soself = (PyStructObject *)self; |  | ||||||
| 	assert(PyStruct_Check(self)); | 	assert(PyStruct_Check(self)); | ||||||
| 	assert(soself->s_codes != NULL);	 | 	assert(soself->s_codes != NULL);	 | ||||||
| 	if (inputstr == NULL || !PyString_Check(inputstr) || | 	if (inputstr == NULL || !PyString_Check(inputstr) || | ||||||
| 	    PyString_GET_SIZE(inputstr) != soself->s_size) { | 		PyString_GET_SIZE(inputstr) != soself->s_size) { | ||||||
| 		PyErr_Format(StructError, | 		PyErr_Format(StructError, | ||||||
| 			"unpack requires a string argument of length %d", soself->s_size); | 			"unpack requires a string argument of length %d", soself->s_size); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
| 	result = PyTuple_New(soself->s_len); | 	return s_unpack_internal(soself, PyString_AS_STRING(inputstr)); | ||||||
| 	if (result == NULL) | } | ||||||
|  | 
 | ||||||
|  | PyDoc_STRVAR(s_unpack_from__doc__, | ||||||
|  | "unpack_from(buffer[, offset]) -> (v1, v2, ...)\n\
 | ||||||
|  | \n\ | ||||||
|  | Return tuple containing values unpacked according to this Struct's format.\n\ | ||||||
|  | Unlike unpack, unpack_from can unpack values from any object supporting\n\ | ||||||
|  | the buffer API, not just str. Requires len(buffer[offset:]) >= self.size.\n\ | ||||||
|  | See struct.__doc__ for more on format strings."); | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | s_unpack_from(PyObject *self, PyObject *args, PyObject *kwds) | ||||||
|  | { | ||||||
|  | 	static char *kwlist[] = {"buffer", "offset", 0}; | ||||||
|  | #if (PY_VERSION_HEX < 0x02050000) | ||||||
|  | 	static char *fmt = "z#|i:unpack_from"; | ||||||
|  | #else | ||||||
|  | 	static char *fmt = "z#|n:unpack_from"; | ||||||
|  | #endif | ||||||
|  | 	Py_ssize_t buffer_len = 0, offset = 0; | ||||||
|  | 	char *buffer = NULL; | ||||||
|  | 	PyStructObject *soself = (PyStructObject *)self; | ||||||
|  | 	assert(PyStruct_Check(self)); | ||||||
|  | 	assert(soself->s_codes != NULL); | ||||||
|  | 
 | ||||||
|  | 	if (!PyArg_ParseTupleAndKeywords(args, kwds, fmt, kwlist, | ||||||
|  | 					 &buffer, &buffer_len, &offset)) | ||||||
|  |         	return NULL; | ||||||
|  | 
 | ||||||
|  | 	if (buffer == NULL) { | ||||||
|  | 		PyErr_Format(StructError, | ||||||
|  | 			"unpack_from requires a buffer argument"); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	 |  | ||||||
| 
 |  | ||||||
| 	restart = PyString_AS_STRING(inputstr); |  | ||||||
| 	i = 0; |  | ||||||
| 	for (code = soself->s_codes; code->fmtdef != NULL; code++) { |  | ||||||
| 		Py_ssize_t n; |  | ||||||
| 		PyObject *v; |  | ||||||
| 		const formatdef *e = code->fmtdef; |  | ||||||
| 		const char *res = restart + code->offset; |  | ||||||
| 		if (e->format == 's') { |  | ||||||
| 			v = PyString_FromStringAndSize(res, code->repeat); |  | ||||||
| 			if (v == NULL) |  | ||||||
| 				goto fail; |  | ||||||
| 			PyTuple_SET_ITEM(result, i++, v); |  | ||||||
| 		} else if (e->format == 'p') { |  | ||||||
| 			n = *(unsigned char*)res; |  | ||||||
| 			if (n >= code->repeat) |  | ||||||
| 				n = code->repeat - 1; |  | ||||||
| 			v = PyString_FromStringAndSize(res + 1, n); |  | ||||||
| 			if (v == NULL) |  | ||||||
| 				goto fail; |  | ||||||
| 			PyTuple_SET_ITEM(result, i++, v); |  | ||||||
| 		} else { |  | ||||||
| 			for (n = 0; n < code->repeat; n++) { |  | ||||||
| 				v = e->unpack(res, e); |  | ||||||
| 				if (v == NULL) |  | ||||||
| 					goto fail; |  | ||||||
| 				PyTuple_SET_ITEM(result, i++, v); |  | ||||||
| 				res += e->size; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	return result; | 	if (offset < 0) | ||||||
| fail: | 		offset += buffer_len; | ||||||
| 	Py_DECREF(result); |  | ||||||
| 	return NULL; |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
|  | 	if (offset < 0 || (buffer_len - offset) < soself->s_size) { | ||||||
|  | 		PyErr_Format(StructError, | ||||||
|  | 			"unpack_from requires a buffer of at least %d bytes", | ||||||
|  | 			soself->s_size); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	return s_unpack_internal(soself, buffer + offset); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| PyDoc_STRVAR(s_pack__doc__, | PyDoc_STRVAR(s_pack__doc__, | ||||||
| "pack(v1, v2, ...) -> string\n\
 | "pack(v1, v2, ...) -> string\n\
 | ||||||
|  | @ -1225,8 +1273,8 @@ s_pack(PyObject *self, PyObject *args) | ||||||
| 				goto fail; | 				goto fail; | ||||||
| 			} | 			} | ||||||
| 			n = PyString_GET_SIZE(v); | 			n = PyString_GET_SIZE(v); | ||||||
| 			if (n > code->repeat) | 			if (n > code->size) | ||||||
| 				n = code->repeat; | 				n = code->size; | ||||||
| 			if (n > 0) | 			if (n > 0) | ||||||
| 				memcpy(res, PyString_AS_STRING(v), n); | 				memcpy(res, PyString_AS_STRING(v), n); | ||||||
| 		} else if (e->format == 'p') { | 		} else if (e->format == 'p') { | ||||||
|  | @ -1237,20 +1285,17 @@ s_pack(PyObject *self, PyObject *args) | ||||||
| 				goto fail; | 				goto fail; | ||||||
| 			} | 			} | ||||||
| 			n = PyString_GET_SIZE(v); | 			n = PyString_GET_SIZE(v); | ||||||
| 			if (n > (code->repeat - 1)) | 			if (n > (code->size - 1)) | ||||||
| 				n = code->repeat - 1; | 				n = code->size - 1; | ||||||
| 			if (n > 0) | 			if (n > 0) | ||||||
| 				memcpy(res + 1, PyString_AS_STRING(v), n); | 				memcpy(res + 1, PyString_AS_STRING(v), n); | ||||||
| 			if (n > 255) | 			if (n > 255) | ||||||
| 				n = 255; | 				n = 255; | ||||||
| 			*res = Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char); | 			*res = Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char); | ||||||
| 		} else { | 		} else { | ||||||
| 			for (n = 0; n < code->repeat; n++) { | 			v = PyTuple_GET_ITEM(args, i++); | ||||||
| 				v = PyTuple_GET_ITEM(args, i++); | 			if (e->pack(res, v, e) < 0) | ||||||
| 				if (e->pack(res, v, e) < 0) | 				goto fail; | ||||||
| 					goto fail; |  | ||||||
| 				res += e->size; |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | @ -1266,8 +1311,9 @@ s_pack(PyObject *self, PyObject *args) | ||||||
| /* List of functions */ | /* List of functions */ | ||||||
| 
 | 
 | ||||||
| static struct PyMethodDef s_methods[] = { | static struct PyMethodDef s_methods[] = { | ||||||
| 	{"pack",	s_pack,		METH_VARARGS, s_pack__doc__}, | 	{"pack",	(PyCFunction)s_pack,		METH_VARARGS, s_pack__doc__}, | ||||||
| 	{"unpack",	s_unpack,	METH_O, s_unpack__doc__}, | 	{"unpack",	(PyCFunction)s_unpack,		METH_O, s_unpack__doc__}, | ||||||
|  | 	{"unpack_from",	(PyCFunction)s_unpack_from,	METH_KEYWORDS, s_unpack_from__doc__}, | ||||||
| 	{NULL,	 NULL}		/* sentinel */ | 	{NULL,	 NULL}		/* sentinel */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Bob Ippolito
						Bob Ippolito