1 /**
2 * Copyright (c) 2017-present, Gregory Szorc
3 * All rights reserved.
4 *
5 * This software may be modified and distributed under the terms
6 * of the BSD license. See the LICENSE file for details.
7 */
8 
9 #include "python-zstandard.h"
10 
11 extern PyObject* ZstdError;
12 
13 PyDoc_STRVAR(FrameParameters__doc__,
14 	"FrameParameters: information about a zstd frame");
15 
get_frame_parameters(PyObject * self,PyObject * args,PyObject * kwargs)16 FrameParametersObject* get_frame_parameters(PyObject* self, PyObject* args, PyObject* kwargs) {
17 	static char* kwlist[] = {
18 		"data",
19 		NULL
20 	};
21 
22 	Py_buffer source;
23 	ZSTD_frameHeader header;
24 	FrameParametersObject* result = NULL;
25 	size_t zresult;
26 
27 #if PY_MAJOR_VERSION >= 3
28 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*:get_frame_parameters",
29 #else
30 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s*:get_frame_parameters",
31 #endif
32 		kwlist, &source)) {
33 		return NULL;
34 	}
35 
36 	if (!PyBuffer_IsContiguous(&source, 'C') || source.ndim > 1) {
37 		PyErr_SetString(PyExc_ValueError,
38 			"data buffer should be contiguous and have at most one dimension");
39 		goto finally;
40 	}
41 
42 	zresult = ZSTD_getFrameHeader(&header, source.buf, source.len);
43 
44 	if (ZSTD_isError(zresult)) {
45 		PyErr_Format(ZstdError, "cannot get frame parameters: %s", ZSTD_getErrorName(zresult));
46 		goto finally;
47 	}
48 
49 	if (zresult) {
50 		PyErr_Format(ZstdError, "not enough data for frame parameters; need %zu bytes", zresult);
51 		goto finally;
52 	}
53 
54 	result = PyObject_New(FrameParametersObject, &FrameParametersType);
55 	if (!result) {
56 		goto finally;
57 	}
58 
59 	result->frameContentSize = header.frameContentSize;
60 	result->windowSize = header.windowSize;
61 	result->dictID = header.dictID;
62 	result->checksumFlag = header.checksumFlag ? 1 : 0;
63 
64 finally:
65 	PyBuffer_Release(&source);
66 	return result;
67 }
68 
FrameParameters_dealloc(PyObject * self)69 static void FrameParameters_dealloc(PyObject* self) {
70 	PyObject_Del(self);
71 }
72 
73 static PyMemberDef FrameParameters_members[] = {
74 	{ "content_size", T_ULONGLONG,
75 	  offsetof(FrameParametersObject, frameContentSize), READONLY,
76 	  "frame content size" },
77 	{ "window_size", T_ULONGLONG,
78 	  offsetof(FrameParametersObject, windowSize), READONLY,
79 	  "window size" },
80 	{ "dict_id", T_UINT,
81 	  offsetof(FrameParametersObject, dictID), READONLY,
82 	  "dictionary ID" },
83 	{ "has_checksum", T_BOOL,
84 	  offsetof(FrameParametersObject, checksumFlag), READONLY,
85 	  "checksum flag" },
86 	{ NULL }
87 };
88 
89 PyTypeObject FrameParametersType = {
90 	PyVarObject_HEAD_INIT(NULL, 0)
91 	"FrameParameters",          /* tp_name */
92 	sizeof(FrameParametersObject), /* tp_basicsize */
93 	0,                         /* tp_itemsize */
94 	(destructor)FrameParameters_dealloc, /* tp_dealloc */
95 	0,                         /* tp_print */
96 	0,                         /* tp_getattr */
97 	0,                         /* tp_setattr */
98 	0,                         /* tp_compare */
99 	0,                         /* tp_repr */
100 	0,                         /* tp_as_number */
101 	0,                         /* tp_as_sequence */
102 	0,                         /* tp_as_mapping */
103 	0,                         /* tp_hash  */
104 	0,                         /* tp_call */
105 	0,                         /* tp_str */
106 	0,                         /* tp_getattro */
107 	0,                         /* tp_setattro */
108 	0,                         /* tp_as_buffer */
109 	Py_TPFLAGS_DEFAULT,        /* tp_flags */
110 	FrameParameters__doc__,    /* tp_doc */
111 	0,                         /* tp_traverse */
112 	0,                         /* tp_clear */
113 	0,                         /* tp_richcompare */
114 	0,                         /* tp_weaklistoffset */
115 	0,                         /* tp_iter */
116 	0,                         /* tp_iternext */
117 	0,                         /* tp_methods */
118 	FrameParameters_members,   /* tp_members */
119 	0,                         /* tp_getset */
120 	0,                         /* tp_base */
121 	0,                         /* tp_dict */
122 	0,                         /* tp_descr_get */
123 	0,                         /* tp_descr_set */
124 	0,                         /* tp_dictoffset */
125 	0,                         /* tp_init */
126 	0,                         /* tp_alloc */
127 	0,                         /* tp_new */
128 };
129 
frameparams_module_init(PyObject * mod)130 void frameparams_module_init(PyObject* mod) {
131 	Py_SET_TYPE(&FrameParametersType, &PyType_Type);
132 	if (PyType_Ready(&FrameParametersType) < 0) {
133 		return;
134 	}
135 
136 	Py_INCREF(&FrameParametersType);
137 	PyModule_AddObject(mod, "FrameParameters", (PyObject*)&FrameParametersType);
138 }
139