1 /*
2  * Python object wrapper of libolecf_property_set_t
3  *
4  * Copyright (C) 2008-2021, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <types.h>
24 
25 #if defined( HAVE_STDLIB_H ) || defined( HAVE_WINAPI )
26 #include <stdlib.h>
27 #endif
28 
29 #include "pyolecf_error.h"
30 #include "pyolecf_guid.h"
31 #include "pyolecf_libcerror.h"
32 #include "pyolecf_libolecf.h"
33 #include "pyolecf_property_section.h"
34 #include "pyolecf_property_sections.h"
35 #include "pyolecf_property_set.h"
36 #include "pyolecf_python.h"
37 #include "pyolecf_unused.h"
38 
39 PyMethodDef pyolecf_property_set_object_methods[] = {
40 
41 	{ "get_class_identifier",
42 	  (PyCFunction) pyolecf_property_set_get_class_identifier,
43 	  METH_NOARGS,
44 	  "get_class_identifier() -> Unicode string or None\n"
45 	  "\n"
46 	  "Retrieves the class identifier." },
47 
48 	{ "get_number_of_sections",
49 	  (PyCFunction) pyolecf_property_set_get_number_of_sections,
50 	  METH_NOARGS,
51 	  "get_number_of_sections() -> Integer or None\n"
52 	  "\n"
53 	  "Retrieves the number of sections." },
54 
55 	{ "get_section",
56 	  (PyCFunction) pyolecf_property_set_get_section,
57 	  METH_VARARGS | METH_KEYWORDS,
58 	  "get_section(section_index) -> Object or None\n"
59 	  "\n"
60 	  "Retrieves the section specified by the index." },
61 
62 	/* Sentinel */
63 	{ NULL, NULL, 0, NULL }
64 };
65 
66 PyGetSetDef pyolecf_property_set_object_get_set_definitions[] = {
67 
68 	{ "class_identifier",
69 	  (getter) pyolecf_property_set_get_class_identifier,
70 	  (setter) 0,
71 	  "The class identifier.",
72 	  NULL },
73 
74 	{ "number_of_sections",
75 	  (getter) pyolecf_property_set_get_number_of_sections,
76 	  (setter) 0,
77 	  "The number of sections.",
78 	  NULL },
79 
80 	{ "sections",
81 	  (getter) pyolecf_property_set_get_sections,
82 	  (setter) 0,
83 	  "The sections.",
84 	  NULL },
85 
86 	/* Sentinel */
87 	{ NULL, NULL, NULL, NULL, NULL }
88 };
89 
90 PyTypeObject pyolecf_property_set_type_object = {
91 	PyVarObject_HEAD_INIT( NULL, 0 )
92 
93 	/* tp_name */
94 	"pyolecf.property_set",
95 	/* tp_basicsize */
96 	sizeof( pyolecf_property_set_t ),
97 	/* tp_itemsize */
98 	0,
99 	/* tp_dealloc */
100 	(destructor) pyolecf_property_set_free,
101 	/* tp_print */
102 	0,
103 	/* tp_getattr */
104 	0,
105 	/* tp_setattr */
106 	0,
107 	/* tp_compare */
108 	0,
109 	/* tp_repr */
110 	0,
111 	/* tp_as_number */
112 	0,
113 	/* tp_as_sequence */
114 	0,
115 	/* tp_as_mapping */
116 	0,
117 	/* tp_hash */
118 	0,
119 	/* tp_call */
120 	0,
121 	/* tp_str */
122 	0,
123 	/* tp_getattro */
124 	0,
125 	/* tp_setattro */
126 	0,
127 	/* tp_as_buffer */
128 	0,
129 	/* tp_flags */
130 	Py_TPFLAGS_DEFAULT,
131 	/* tp_doc */
132 	"pyolecf property set object (wraps libolecf_property_set_t)",
133 	/* tp_traverse */
134 	0,
135 	/* tp_clear */
136 	0,
137 	/* tp_richcompare */
138 	0,
139 	/* tp_weaklistoffset */
140 	0,
141 	/* tp_iter */
142 	0,
143 	/* tp_iternext */
144 	0,
145 	/* tp_methods */
146 	pyolecf_property_set_object_methods,
147 	/* tp_members */
148 	0,
149 	/* tp_getset */
150 	pyolecf_property_set_object_get_set_definitions,
151 	/* tp_base */
152 	0,
153 	/* tp_dict */
154 	0,
155 	/* tp_descr_get */
156 	0,
157 	/* tp_descr_set */
158 	0,
159 	/* tp_dictoffset */
160 	0,
161 	/* tp_init */
162 	(initproc) pyolecf_property_set_init,
163 	/* tp_alloc */
164 	0,
165 	/* tp_new */
166 	0,
167 	/* tp_free */
168 	0,
169 	/* tp_is_gc */
170 	0,
171 	/* tp_bases */
172 	NULL,
173 	/* tp_mro */
174 	NULL,
175 	/* tp_cache */
176 	NULL,
177 	/* tp_subclasses */
178 	NULL,
179 	/* tp_weaklist */
180 	NULL,
181 	/* tp_del */
182 	0
183 };
184 
185 /* Creates a new property set object
186  * Returns a Python object if successful or NULL on error
187  */
pyolecf_property_set_new(libolecf_property_set_t * property_set,PyObject * parent_object)188 PyObject *pyolecf_property_set_new(
189            libolecf_property_set_t *property_set,
190            PyObject *parent_object )
191 {
192 	pyolecf_property_set_t *pyolecf_property_set = NULL;
193 	static char *function                        = "pyolecf_property_set_new";
194 
195 	if( property_set == NULL )
196 	{
197 		PyErr_Format(
198 		 PyExc_ValueError,
199 		 "%s: invalid property set.",
200 		 function );
201 
202 		return( NULL );
203 	}
204 	/* PyObject_New does not invoke tp_init
205 	 */
206 	pyolecf_property_set = PyObject_New(
207 	                        struct pyolecf_property_set,
208 	                        &pyolecf_property_set_type_object );
209 
210 	if( pyolecf_property_set == NULL )
211 	{
212 		PyErr_Format(
213 		 PyExc_MemoryError,
214 		 "%s: unable to initialize property set.",
215 		 function );
216 
217 		goto on_error;
218 	}
219 	pyolecf_property_set->property_set  = property_set;
220 	pyolecf_property_set->parent_object = parent_object;
221 
222 	if( pyolecf_property_set->parent_object != NULL )
223 	{
224 		Py_IncRef(
225 		 pyolecf_property_set->parent_object );
226 	}
227 	return( (PyObject *) pyolecf_property_set );
228 
229 on_error:
230 	if( pyolecf_property_set != NULL )
231 	{
232 		Py_DecRef(
233 		 (PyObject *) pyolecf_property_set );
234 	}
235 	return( NULL );
236 }
237 
238 /* Initializes a property set object
239  * Returns 0 if successful or -1 on error
240  */
pyolecf_property_set_init(pyolecf_property_set_t * pyolecf_property_set)241 int pyolecf_property_set_init(
242      pyolecf_property_set_t *pyolecf_property_set )
243 {
244 	static char *function = "pyolecf_property_set_init";
245 
246 	if( pyolecf_property_set == NULL )
247 	{
248 		PyErr_Format(
249 		 PyExc_ValueError,
250 		 "%s: invalid property set.",
251 		 function );
252 
253 		return( -1 );
254 	}
255 	/* Make sure libolecf property set is set to NULL
256 	 */
257 	pyolecf_property_set->property_set = NULL;
258 
259 	PyErr_Format(
260 	 PyExc_NotImplementedError,
261 	 "%s: initialize of property set not supported.",
262 	 function );
263 
264 	return( -1 );
265 }
266 
267 /* Frees a property set object
268  */
pyolecf_property_set_free(pyolecf_property_set_t * pyolecf_property_set)269 void pyolecf_property_set_free(
270       pyolecf_property_set_t *pyolecf_property_set )
271 {
272 	struct _typeobject *ob_type = NULL;
273 	libcerror_error_t *error    = NULL;
274 	static char *function       = "pyolecf_property_set_free";
275 	int result                  = 0;
276 
277 	if( pyolecf_property_set == NULL )
278 	{
279 		PyErr_Format(
280 		 PyExc_ValueError,
281 		 "%s: invalid property set.",
282 		 function );
283 
284 		return;
285 	}
286 	ob_type = Py_TYPE(
287 	           pyolecf_property_set );
288 
289 	if( ob_type == NULL )
290 	{
291 		PyErr_Format(
292 		 PyExc_ValueError,
293 		 "%s: missing ob_type.",
294 		 function );
295 
296 		return;
297 	}
298 	if( ob_type->tp_free == NULL )
299 	{
300 		PyErr_Format(
301 		 PyExc_ValueError,
302 		 "%s: invalid ob_type - missing tp_free.",
303 		 function );
304 
305 		return;
306 	}
307 	if( pyolecf_property_set->property_set != NULL )
308 	{
309 		Py_BEGIN_ALLOW_THREADS
310 
311 		result = libolecf_property_set_free(
312 		          &( pyolecf_property_set->property_set ),
313 		          &error );
314 
315 		Py_END_ALLOW_THREADS
316 
317 		if( result != 1 )
318 		{
319 			pyolecf_error_raise(
320 			 error,
321 			 PyExc_MemoryError,
322 			 "%s: unable to free libolecf property set.",
323 			 function );
324 
325 			libcerror_error_free(
326 			 &error );
327 		}
328 	}
329 	if( pyolecf_property_set->parent_object != NULL )
330 	{
331 		Py_DecRef(
332 		 pyolecf_property_set->parent_object );
333 	}
334 	ob_type->tp_free(
335 	 (PyObject*) pyolecf_property_set );
336 }
337 
338 /* Retrieves the class identifier
339  * Returns a Python object if successful or NULL on error
340  */
pyolecf_property_set_get_class_identifier(pyolecf_property_set_t * pyolecf_property_set,PyObject * arguments PYOLECF_ATTRIBUTE_UNUSED)341 PyObject *pyolecf_property_set_get_class_identifier(
342            pyolecf_property_set_t *pyolecf_property_set,
343            PyObject *arguments PYOLECF_ATTRIBUTE_UNUSED )
344 {
345 	uint8_t guid_data[ 16 ];
346 
347 	PyObject *string_object  = NULL;
348 	libcerror_error_t *error = NULL;
349 	static char *function    = "pyolecf_property_set_get_class_identifier";
350 	int result               = 0;
351 
352 	PYOLECF_UNREFERENCED_PARAMETER( arguments )
353 
354 	if( pyolecf_property_set == NULL )
355 	{
356 		PyErr_Format(
357 		 PyExc_ValueError,
358 		 "%s: invalid property set.",
359 		 function );
360 
361 		return( NULL );
362 	}
363 	Py_BEGIN_ALLOW_THREADS
364 
365 	result = libolecf_property_set_get_class_identifier(
366 	          pyolecf_property_set->property_set,
367 	          guid_data,
368 	          16,
369 	          &error );
370 
371 	Py_END_ALLOW_THREADS
372 
373 	if( result == -1 )
374 	{
375 		pyolecf_error_raise(
376 		 error,
377 		 PyExc_IOError,
378 		 "%s: unable to retrieve class identifier.",
379 		 function );
380 
381 		libcerror_error_free(
382 		 &error );
383 
384 		return( NULL );
385 	}
386 	else if( result == 0 )
387 	{
388 		Py_IncRef(
389 		 Py_None );
390 
391 		return( Py_None );
392 	}
393 	string_object = pyolecf_string_new_from_guid(
394 	                 guid_data,
395 	                 16 );
396 
397 	return( string_object );
398 }
399 
400 /* Retrieves the number of sections
401  * Returns a Python object if successful or NULL on error
402  */
pyolecf_property_set_get_number_of_sections(pyolecf_property_set_t * pyolecf_property_set,PyObject * arguments PYOLECF_ATTRIBUTE_UNUSED)403 PyObject *pyolecf_property_set_get_number_of_sections(
404            pyolecf_property_set_t *pyolecf_property_set,
405            PyObject *arguments PYOLECF_ATTRIBUTE_UNUSED )
406 {
407 	PyObject *integer_object = NULL;
408 	libcerror_error_t *error = NULL;
409 	static char *function    = "pyolecf_property_set_get_number_of_sections";
410 	int number_of_sections   = 0;
411 	int result               = 0;
412 
413 	PYOLECF_UNREFERENCED_PARAMETER( arguments )
414 
415 	if( pyolecf_property_set == NULL )
416 	{
417 		PyErr_Format(
418 		 PyExc_ValueError,
419 		 "%s: invalid property set.",
420 		 function );
421 
422 		return( NULL );
423 	}
424 	Py_BEGIN_ALLOW_THREADS
425 
426 	result = libolecf_property_set_get_number_of_sections(
427 	          pyolecf_property_set->property_set,
428 	          &number_of_sections,
429 	          &error );
430 
431 	Py_END_ALLOW_THREADS
432 
433 	if( result != 1 )
434 	{
435 		pyolecf_error_raise(
436 		 error,
437 		 PyExc_IOError,
438 		 "%s: unable to retrieve number of sections.",
439 		 function );
440 
441 		libcerror_error_free(
442 		 &error );
443 
444 		return( NULL );
445 	}
446 #if PY_MAJOR_VERSION >= 3
447 	integer_object = PyLong_FromLong(
448 	                  (long) number_of_sections );
449 #else
450 	integer_object = PyInt_FromLong(
451 	                  (long) number_of_sections );
452 #endif
453 	return( integer_object );
454 }
455 
456 /* Retrieves a specific section by index
457  * Returns a Python object if successful or NULL on error
458  */
pyolecf_property_set_get_section_by_index(PyObject * pyolecf_property_set,int section_index)459 PyObject *pyolecf_property_set_get_section_by_index(
460            PyObject *pyolecf_property_set,
461            int section_index )
462 {
463 	PyObject *section_object             = NULL;
464 	libcerror_error_t *error             = NULL;
465 	libolecf_property_section_t *section = NULL;
466 	static char *function                = "pyolecf_property_set_get_section_by_index";
467 	int result                           = 0;
468 
469 	if( pyolecf_property_set == NULL )
470 	{
471 		PyErr_Format(
472 		 PyExc_ValueError,
473 		 "%s: invalid property set.",
474 		 function );
475 
476 		return( NULL );
477 	}
478 	Py_BEGIN_ALLOW_THREADS
479 
480 	result = libolecf_property_set_get_section_by_index(
481 	          ( (pyolecf_property_set_t *) pyolecf_property_set )->property_set,
482 	          section_index,
483 	          &section,
484 	          &error );
485 
486 	Py_END_ALLOW_THREADS
487 
488 	if( result != 1 )
489 	{
490 		pyolecf_error_raise(
491 		 error,
492 		 PyExc_IOError,
493 		 "%s: unable to retrieve section: %d.",
494 		 function,
495 		 section_index );
496 
497 		libcerror_error_free(
498 		 &error );
499 
500 		goto on_error;
501 	}
502 	section_object = pyolecf_property_section_new(
503 	                  section,
504 	                  (PyObject *) pyolecf_property_set );
505 
506 	if( section_object == NULL )
507 	{
508 		PyErr_Format(
509 		 PyExc_MemoryError,
510 		 "%s: unable to create property section object.",
511 		 function );
512 
513 		goto on_error;
514 	}
515 	return( section_object );
516 
517 on_error:
518 	if( section != NULL )
519 	{
520 		libolecf_property_section_free(
521 		 &section,
522 		 NULL );
523 	}
524 	return( NULL );
525 }
526 
527 /* Retrieves a specific section
528  * Returns a Python object if successful or NULL on error
529  */
pyolecf_property_set_get_section(pyolecf_property_set_t * pyolecf_property_set,PyObject * arguments,PyObject * keywords)530 PyObject *pyolecf_property_set_get_section(
531            pyolecf_property_set_t *pyolecf_property_set,
532            PyObject *arguments,
533            PyObject *keywords )
534 {
535 	PyObject *section_object    = NULL;
536 	static char *keyword_list[] = { "section_index", NULL };
537 	int section_index           = 0;
538 
539 	if( PyArg_ParseTupleAndKeywords(
540 	     arguments,
541 	     keywords,
542 	     "i",
543 	     keyword_list,
544 	     &section_index ) == 0 )
545 	{
546 		return( NULL );
547 	}
548 	section_object = pyolecf_property_set_get_section_by_index(
549 	                  (PyObject *) pyolecf_property_set,
550 	                  section_index );
551 
552 	return( section_object );
553 }
554 
555 /* Retrieves a sequence and iterator object for the sections
556  * Returns a Python object if successful or NULL on error
557  */
pyolecf_property_set_get_sections(pyolecf_property_set_t * pyolecf_property_set,PyObject * arguments PYOLECF_ATTRIBUTE_UNUSED)558 PyObject *pyolecf_property_set_get_sections(
559            pyolecf_property_set_t *pyolecf_property_set,
560            PyObject *arguments PYOLECF_ATTRIBUTE_UNUSED )
561 {
562 	PyObject *sequence_object = NULL;
563 	libcerror_error_t *error  = NULL;
564 	static char *function     = "pyolecf_property_set_get_sections";
565 	int number_of_sections    = 0;
566 	int result                = 0;
567 
568 	PYOLECF_UNREFERENCED_PARAMETER( arguments )
569 
570 	if( pyolecf_property_set == NULL )
571 	{
572 		PyErr_Format(
573 		 PyExc_ValueError,
574 		 "%s: invalid property set.",
575 		 function );
576 
577 		return( NULL );
578 	}
579 	Py_BEGIN_ALLOW_THREADS
580 
581 	result = libolecf_property_set_get_number_of_sections(
582 	          pyolecf_property_set->property_set,
583 	          &number_of_sections,
584 	          &error );
585 
586 	Py_END_ALLOW_THREADS
587 
588 	if( result != 1 )
589 	{
590 		pyolecf_error_raise(
591 		 error,
592 		 PyExc_IOError,
593 		 "%s: unable to retrieve number of sections.",
594 		 function );
595 
596 		libcerror_error_free(
597 		 &error );
598 
599 		return( NULL );
600 	}
601 	sequence_object = pyolecf_property_sections_new(
602 	                   (PyObject *) pyolecf_property_set,
603 	                   &pyolecf_property_set_get_section_by_index,
604 	                   number_of_sections );
605 
606 	if( sequence_object == NULL )
607 	{
608 		pyolecf_error_raise(
609 		 error,
610 		 PyExc_MemoryError,
611 		 "%s: unable to create sequence object.",
612 		 function );
613 
614 		return( NULL );
615 	}
616 	return( sequence_object );
617 }
618 
619