@@ -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