@@ -26,7 +26,7 @@ class _zstd.ZstdDict "ZstdDict *" "&zstd_dict_type_spec"
2626/*[clinic input]
2727@classmethod
2828_zstd.ZstdDict.__new__ as _zstd_ZstdDict_new
29- dict_content: object
29+ dict_content: Py_buffer
3030 The content of a Zstandard dictionary as a bytes-like object.
3131 /
3232 *
@@ -42,17 +42,25 @@ by multiple ZstdCompressor or ZstdDecompressor objects.
4242[clinic start generated code]*/
4343
4444static PyObject *
45- _zstd_ZstdDict_new_impl (PyTypeObject * type , PyObject * dict_content ,
45+ _zstd_ZstdDict_new_impl (PyTypeObject * type , Py_buffer * dict_content ,
4646 int is_raw )
47- /*[clinic end generated code: output=3ebff839cb3be6d7 input=6b5de413869ae878 ]*/
47+ /*[clinic end generated code: output=685b7406a48b0949 input=9e8c493e31c98383 ]*/
4848{
49+ /* All dictionaries must be at least 8 bytes */
50+ if (dict_content -> len < 8 ) {
51+ PyErr_SetString (PyExc_ValueError ,
52+ "Zstandard dictionary content too short "
53+ "(must have at least eight bytes)" );
54+ return NULL ;
55+ }
56+
4957 ZstdDict * self = PyObject_GC_New (ZstdDict , type );
5058 if (self == NULL ) {
51- goto error ;
59+ return NULL ;
5260 }
5361
54- self -> dict_content = NULL ;
5562 self -> d_dict = NULL ;
63+ self -> dict_buffer = NULL ;
5664 self -> dict_id = 0 ;
5765 self -> lock = (PyMutex ){0 };
5866
@@ -62,39 +70,26 @@ _zstd_ZstdDict_new_impl(PyTypeObject *type, PyObject *dict_content,
6270 goto error ;
6371 }
6472
65- /* Check dict_content's type */
66- self -> dict_content = PyBytes_FromObject (dict_content );
67- if (self -> dict_content == NULL ) {
68- PyErr_SetString (PyExc_TypeError ,
69- "dict_content argument should be bytes-like object." );
70- goto error ;
71- }
72-
73- /* Both ordinary dictionary and "raw content" dictionary should
74- at least 8 bytes */
75- if (Py_SIZE (self -> dict_content ) < 8 ) {
76- PyErr_SetString (PyExc_ValueError ,
77- "Zstandard dictionary content should at least "
78- "8 bytes." );
73+ self -> dict_buffer = PyMem_Malloc (dict_content -> len );
74+ if (!self -> dict_buffer ) {
75+ PyErr_NoMemory ();
7976 goto error ;
8077 }
78+ memcpy (self -> dict_buffer , dict_content -> buf , dict_content -> len );
79+ self -> dict_len = dict_content -> len ;
8180
8281 /* Get dict_id, 0 means "raw content" dictionary. */
83- self -> dict_id = ZSTD_getDictID_fromDict (
84- PyBytes_AS_STRING (self -> dict_content ),
85- Py_SIZE (self -> dict_content ));
82+ self -> dict_id = ZSTD_getDictID_fromDict (self -> dict_buffer , self -> dict_len );
8683
8784 /* Check validity for ordinary dictionary */
8885 if (!is_raw && self -> dict_id == 0 ) {
89- char * msg = "Invalid Zstandard dictionary and is_raw not set.\n" ;
90- PyErr_SetString (PyExc_ValueError , msg );
86+ PyErr_SetString (PyExc_ValueError , "invalid Zstandard dictionary" );
9187 goto error ;
9288 }
9389
94- // Can only track self once self->dict_content is included
9590 PyObject_GC_Track (self );
9691
97- return (PyObject * )self ;
92+ return (PyObject * )self ;
9893
9994error :
10095 Py_XDECREF (self );
@@ -115,12 +110,12 @@ ZstdDict_dealloc(PyObject *ob)
115110
116111 assert (!PyMutex_IsLocked (& self -> lock ));
117112
118- /* Release dict_content after Free ZSTD_CDict/ZSTD_DDict instances */
119- Py_CLEAR (self -> dict_content );
113+ /* Release dict_buffer after freeing ZSTD_CDict/ZSTD_DDict instances */
114+ PyMem_Free (self -> dict_buffer );
120115 Py_CLEAR (self -> c_dicts );
121116
122117 PyTypeObject * tp = Py_TYPE (self );
123- PyObject_GC_Del ( ob );
118+ tp -> tp_free ( self );
124119 Py_DECREF (tp );
125120}
126121
@@ -131,25 +126,33 @@ PyDoc_STRVAR(ZstdDict_dictid_doc,
131126"The special value '0' means a 'raw content' dictionary,"
132127"without any restrictions on format or content." );
133128
134- PyDoc_STRVAR (ZstdDict_dictcontent_doc ,
135- "The content of a Zstandard dictionary, as a bytes object." );
136-
137129static PyObject *
138- ZstdDict_str (PyObject * ob )
130+ ZstdDict_repr (PyObject * ob )
139131{
140132 ZstdDict * dict = ZstdDict_CAST (ob );
141133 return PyUnicode_FromFormat ("<ZstdDict dict_id=%u dict_size=%zd>" ,
142- dict -> dict_id , Py_SIZE ( dict -> dict_content ) );
134+ ( unsigned int ) dict -> dict_id , dict -> dict_len );
143135}
144136
145137static PyMemberDef ZstdDict_members [] = {
146- {"dict_id" , Py_T_UINT , offsetof(ZstdDict , dict_id ), Py_READONLY ,
147- ZstdDict_dictid_doc },
148- {"dict_content" , Py_T_OBJECT_EX , offsetof(ZstdDict , dict_content ),
149- Py_READONLY , ZstdDict_dictcontent_doc },
138+ {"dict_id" , Py_T_UINT , offsetof(ZstdDict , dict_id ), Py_READONLY , ZstdDict_dictid_doc },
150139 {NULL }
151140};
152141
142+ /*[clinic input]
143+ @getter
144+ _zstd.ZstdDict.dict_content
145+
146+ The content of a Zstandard dictionary, as a bytes object.
147+ [clinic start generated code]*/
148+
149+ static PyObject *
150+ _zstd_ZstdDict_dict_content_get_impl (ZstdDict * self )
151+ /*[clinic end generated code: output=0d05caa5b550eabb input=4ed526d1c151c596]*/
152+ {
153+ return PyBytes_FromStringAndSize (self -> dict_buffer , self -> dict_len );
154+ }
155+
153156/*[clinic input]
154157@getter
155158_zstd.ZstdDict.as_digested_dict
@@ -219,6 +222,7 @@ _zstd_ZstdDict_as_prefix_get_impl(ZstdDict *self)
219222}
220223
221224static PyGetSetDef ZstdDict_getset [] = {
225+ _ZSTD_ZSTDDICT_DICT_CONTENT_GETSETDEF
222226 _ZSTD_ZSTDDICT_AS_DIGESTED_DICT_GETSETDEF
223227 _ZSTD_ZSTDDICT_AS_UNDIGESTED_DICT_GETSETDEF
224228 _ZSTD_ZSTDDICT_AS_PREFIX_GETSETDEF
@@ -229,24 +233,22 @@ static Py_ssize_t
229233ZstdDict_length (PyObject * ob )
230234{
231235 ZstdDict * self = ZstdDict_CAST (ob );
232- assert (PyBytes_Check (self -> dict_content ));
233- return Py_SIZE (self -> dict_content );
236+ return self -> dict_len ;
234237}
235238
236239static int
237240ZstdDict_traverse (PyObject * ob , visitproc visit , void * arg )
238241{
239242 ZstdDict * self = ZstdDict_CAST (ob );
240243 Py_VISIT (self -> c_dicts );
241- Py_VISIT (self -> dict_content );
242244 return 0 ;
243245}
244246
245247static int
246248ZstdDict_clear (PyObject * ob )
247249{
248250 ZstdDict * self = ZstdDict_CAST (ob );
249- Py_CLEAR (self -> dict_content );
251+ Py_CLEAR (self -> c_dicts );
250252 return 0 ;
251253}
252254
@@ -255,7 +257,7 @@ static PyType_Slot zstddict_slots[] = {
255257 {Py_tp_getset , ZstdDict_getset },
256258 {Py_tp_new , _zstd_ZstdDict_new },
257259 {Py_tp_dealloc , ZstdDict_dealloc },
258- {Py_tp_str , ZstdDict_str },
260+ {Py_tp_repr , ZstdDict_repr },
259261 {Py_tp_doc , (void * )_zstd_ZstdDict_new__doc__ },
260262 {Py_sq_length , ZstdDict_length },
261263 {Py_tp_traverse , ZstdDict_traverse },
0 commit comments