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