1 /*
2  * Python object wrapper of libesedb_column_t
3  *
4  * Copyright (C) 2009-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 "pyesedb_column.h"
30 #include "pyesedb_error.h"
31 #include "pyesedb_libcerror.h"
32 #include "pyesedb_libesedb.h"
33 #include "pyesedb_python.h"
34 #include "pyesedb_unused.h"
35 
36 PyMethodDef pyesedb_column_object_methods[] = {
37 
38 	{ "get_identifier",
39 	  (PyCFunction) pyesedb_column_get_identifier,
40 	  METH_NOARGS,
41 	  "get_identifier() -> Integer\n"
42 	  "\n"
43 	  "Retrieves the identifier." },
44 
45 	{ "get_type",
46 	  (PyCFunction) pyesedb_column_get_type,
47 	  METH_NOARGS,
48 	  "get_type() -> Integer\n"
49 	  "\n"
50 	  "Retrieves the type." },
51 
52 	{ "get_name",
53 	  (PyCFunction) pyesedb_column_get_name,
54 	  METH_NOARGS,
55 	  "get_name() -> Unicode string\n"
56 	  "\n"
57 	  "Retrieves the name." },
58 
59 	/* Sentinel */
60 	{ NULL, NULL, 0, NULL }
61 };
62 
63 PyGetSetDef pyesedb_column_object_get_set_definitions[] = {
64 
65 	{ "identifier",
66 	  (getter) pyesedb_column_get_identifier,
67 	  (setter) 0,
68 	  "The identifier.",
69 	  NULL },
70 
71 	{ "type",
72 	  (getter) pyesedb_column_get_type,
73 	  (setter) 0,
74 	  "The type.",
75 	  NULL },
76 
77 	{ "name",
78 	  (getter) pyesedb_column_get_name,
79 	  (setter) 0,
80 	  "The name.",
81 	  NULL },
82 
83 	/* Sentinel */
84 	{ NULL, NULL, NULL, NULL, NULL }
85 };
86 
87 PyTypeObject pyesedb_column_type_object = {
88 	PyVarObject_HEAD_INIT( NULL, 0 )
89 
90 	/* tp_name */
91 	"pyesedb.column",
92 	/* tp_basicsize */
93 	sizeof( pyesedb_column_t ),
94 	/* tp_itemsize */
95 	0,
96 	/* tp_dealloc */
97 	(destructor) pyesedb_column_free,
98 	/* tp_print */
99 	0,
100 	/* tp_getattr */
101 	0,
102 	/* tp_setattr */
103 	0,
104 	/* tp_compare */
105 	0,
106 	/* tp_repr */
107 	0,
108 	/* tp_as_number */
109 	0,
110 	/* tp_as_sequence */
111 	0,
112 	/* tp_as_mapping */
113 	0,
114 	/* tp_hash */
115 	0,
116 	/* tp_call */
117 	0,
118 	/* tp_str */
119 	0,
120 	/* tp_getattro */
121 	0,
122 	/* tp_setattro */
123 	0,
124 	/* tp_as_buffer */
125 	0,
126 	/* tp_flags */
127 	Py_TPFLAGS_DEFAULT,
128 	/* tp_doc */
129 	"pyesedb column object (wraps libesedb_column_t)",
130 	/* tp_traverse */
131 	0,
132 	/* tp_clear */
133 	0,
134 	/* tp_richcompare */
135 	0,
136 	/* tp_weaklistoffset */
137 	0,
138 	/* tp_iter */
139 	0,
140 	/* tp_iternext */
141 	0,
142 	/* tp_methods */
143 	pyesedb_column_object_methods,
144 	/* tp_members */
145 	0,
146 	/* tp_getset */
147 	pyesedb_column_object_get_set_definitions,
148 	/* tp_base */
149 	0,
150 	/* tp_dict */
151 	0,
152 	/* tp_descr_get */
153 	0,
154 	/* tp_descr_set */
155 	0,
156 	/* tp_dictoffset */
157 	0,
158 	/* tp_init */
159 	(initproc) pyesedb_column_init,
160 	/* tp_alloc */
161 	0,
162 	/* tp_new */
163 	0,
164 	/* tp_free */
165 	0,
166 	/* tp_is_gc */
167 	0,
168 	/* tp_bases */
169 	NULL,
170 	/* tp_mro */
171 	NULL,
172 	/* tp_cache */
173 	NULL,
174 	/* tp_subclasses */
175 	NULL,
176 	/* tp_weaklist */
177 	NULL,
178 	/* tp_del */
179 	0
180 };
181 
182 /* Creates a new column object
183  * Returns a Python object if successful or NULL on error
184  */
pyesedb_column_new(libesedb_column_t * column,PyObject * parent_object)185 PyObject *pyesedb_column_new(
186            libesedb_column_t *column,
187            PyObject *parent_object )
188 {
189 	pyesedb_column_t *pyesedb_column = NULL;
190 	static char *function            = "pyesedb_column_new";
191 
192 	if( column == NULL )
193 	{
194 		PyErr_Format(
195 		 PyExc_ValueError,
196 		 "%s: invalid column.",
197 		 function );
198 
199 		return( NULL );
200 	}
201 	/* PyObject_New does not invoke tp_init
202 	 */
203 	pyesedb_column = PyObject_New(
204 	                  struct pyesedb_column,
205 	                  &pyesedb_column_type_object );
206 
207 	if( pyesedb_column == NULL )
208 	{
209 		PyErr_Format(
210 		 PyExc_MemoryError,
211 		 "%s: unable to initialize column.",
212 		 function );
213 
214 		goto on_error;
215 	}
216 	pyesedb_column->column        = column;
217 	pyesedb_column->parent_object = parent_object;
218 
219 	if( pyesedb_column->parent_object != NULL )
220 	{
221 		Py_IncRef(
222 		 pyesedb_column->parent_object );
223 	}
224 	return( (PyObject *) pyesedb_column );
225 
226 on_error:
227 	if( pyesedb_column != NULL )
228 	{
229 		Py_DecRef(
230 		 (PyObject *) pyesedb_column );
231 	}
232 	return( NULL );
233 }
234 
235 /* Initializes a column object
236  * Returns 0 if successful or -1 on error
237  */
pyesedb_column_init(pyesedb_column_t * pyesedb_column)238 int pyesedb_column_init(
239      pyesedb_column_t *pyesedb_column )
240 {
241 	static char *function = "pyesedb_column_init";
242 
243 	if( pyesedb_column == NULL )
244 	{
245 		PyErr_Format(
246 		 PyExc_ValueError,
247 		 "%s: invalid column.",
248 		 function );
249 
250 		return( -1 );
251 	}
252 	/* Make sure libesedb column is set to NULL
253 	 */
254 	pyesedb_column->column = NULL;
255 
256 	PyErr_Format(
257 	 PyExc_NotImplementedError,
258 	 "%s: initialize of column not supported.",
259 	 function );
260 
261 	return( -1 );
262 }
263 
264 /* Frees a column object
265  */
pyesedb_column_free(pyesedb_column_t * pyesedb_column)266 void pyesedb_column_free(
267       pyesedb_column_t *pyesedb_column )
268 {
269 	struct _typeobject *ob_type = NULL;
270 	libcerror_error_t *error    = NULL;
271 	static char *function       = "pyesedb_column_free";
272 	int result                  = 0;
273 
274 	if( pyesedb_column == NULL )
275 	{
276 		PyErr_Format(
277 		 PyExc_ValueError,
278 		 "%s: invalid column.",
279 		 function );
280 
281 		return;
282 	}
283 	ob_type = Py_TYPE(
284 	           pyesedb_column );
285 
286 	if( ob_type == NULL )
287 	{
288 		PyErr_Format(
289 		 PyExc_ValueError,
290 		 "%s: missing ob_type.",
291 		 function );
292 
293 		return;
294 	}
295 	if( ob_type->tp_free == NULL )
296 	{
297 		PyErr_Format(
298 		 PyExc_ValueError,
299 		 "%s: invalid ob_type - missing tp_free.",
300 		 function );
301 
302 		return;
303 	}
304 	if( pyesedb_column->column != NULL )
305 	{
306 		Py_BEGIN_ALLOW_THREADS
307 
308 		result = libesedb_column_free(
309 		          &( pyesedb_column->column ),
310 		          &error );
311 
312 		Py_END_ALLOW_THREADS
313 
314 		if( result != 1 )
315 		{
316 			pyesedb_error_raise(
317 			 error,
318 			 PyExc_MemoryError,
319 			 "%s: unable to free libesedb column.",
320 			 function );
321 
322 			libcerror_error_free(
323 			 &error );
324 		}
325 	}
326 	if( pyesedb_column->parent_object != NULL )
327 	{
328 		Py_DecRef(
329 		 pyesedb_column->parent_object );
330 	}
331 	ob_type->tp_free(
332 	 (PyObject*) pyesedb_column );
333 }
334 
335 /* Retrieves the identifier
336  * Returns a Python object if successful or NULL on error
337  */
pyesedb_column_get_identifier(pyesedb_column_t * pyesedb_column,PyObject * arguments PYESEDB_ATTRIBUTE_UNUSED)338 PyObject *pyesedb_column_get_identifier(
339            pyesedb_column_t *pyesedb_column,
340            PyObject *arguments PYESEDB_ATTRIBUTE_UNUSED )
341 {
342 	PyObject *integer_object = NULL;
343 	libcerror_error_t *error = NULL;
344 	static char *function    = "pyesedb_column_get_identifier";
345 	uint32_t value_32bit     = 0;
346 	int result               = 0;
347 
348 	PYESEDB_UNREFERENCED_PARAMETER( arguments )
349 
350 	if( pyesedb_column == NULL )
351 	{
352 		PyErr_Format(
353 		 PyExc_ValueError,
354 		 "%s: invalid column.",
355 		 function );
356 
357 		return( NULL );
358 	}
359 	Py_BEGIN_ALLOW_THREADS
360 
361 	result = libesedb_column_get_identifier(
362 	          pyesedb_column->column,
363 	          &value_32bit,
364 	          &error );
365 
366 	Py_END_ALLOW_THREADS
367 
368 	if( result != 1 )
369 	{
370 		pyesedb_error_raise(
371 		 error,
372 		 PyExc_IOError,
373 		 "%s: unable to retrieve identifier.",
374 		 function );
375 
376 		libcerror_error_free(
377 		 &error );
378 
379 		return( NULL );
380 	}
381 	integer_object = PyLong_FromUnsignedLong(
382 	                  (unsigned long) value_32bit );
383 
384 	return( integer_object );
385 }
386 
387 /* Retrieves the type
388  * Returns a Python object if successful or NULL on error
389  */
pyesedb_column_get_type(pyesedb_column_t * pyesedb_column,PyObject * arguments PYESEDB_ATTRIBUTE_UNUSED)390 PyObject *pyesedb_column_get_type(
391            pyesedb_column_t *pyesedb_column,
392            PyObject *arguments PYESEDB_ATTRIBUTE_UNUSED )
393 {
394 	PyObject *integer_object = NULL;
395 	libcerror_error_t *error = NULL;
396 	static char *function    = "pyesedb_column_get_type";
397 	uint32_t value_32bit     = 0;
398 	int result               = 0;
399 
400 	PYESEDB_UNREFERENCED_PARAMETER( arguments )
401 
402 	if( pyesedb_column == NULL )
403 	{
404 		PyErr_Format(
405 		 PyExc_ValueError,
406 		 "%s: invalid column.",
407 		 function );
408 
409 		return( NULL );
410 	}
411 	Py_BEGIN_ALLOW_THREADS
412 
413 	result = libesedb_column_get_type(
414 	          pyesedb_column->column,
415 	          &value_32bit,
416 	          &error );
417 
418 	Py_END_ALLOW_THREADS
419 
420 	if( result != 1 )
421 	{
422 		pyesedb_error_raise(
423 		 error,
424 		 PyExc_IOError,
425 		 "%s: unable to retrieve type.",
426 		 function );
427 
428 		libcerror_error_free(
429 		 &error );
430 
431 		return( NULL );
432 	}
433 	integer_object = PyLong_FromUnsignedLong(
434 	                  (unsigned long) value_32bit );
435 
436 	return( integer_object );
437 }
438 
439 /* Retrieves the name
440  * Returns a Python object if successful or NULL on error
441  */
pyesedb_column_get_name(pyesedb_column_t * pyesedb_column,PyObject * arguments PYESEDB_ATTRIBUTE_UNUSED)442 PyObject *pyesedb_column_get_name(
443            pyesedb_column_t *pyesedb_column,
444            PyObject *arguments PYESEDB_ATTRIBUTE_UNUSED )
445 {
446 	PyObject *string_object  = NULL;
447 	libcerror_error_t *error = NULL;
448 	const char *errors       = NULL;
449 	static char *function    = "pyesedb_column_get_name";
450 	char *utf8_string        = NULL;
451 	size_t utf8_string_size  = 0;
452 	int result               = 0;
453 
454 	PYESEDB_UNREFERENCED_PARAMETER( arguments )
455 
456 	if( pyesedb_column == NULL )
457 	{
458 		PyErr_Format(
459 		 PyExc_ValueError,
460 		 "%s: invalid column.",
461 		 function );
462 
463 		return( NULL );
464 	}
465 	Py_BEGIN_ALLOW_THREADS
466 
467 	result = libesedb_column_get_utf8_name_size(
468 	          pyesedb_column->column,
469 	          &utf8_string_size,
470 	          &error );
471 
472 	Py_END_ALLOW_THREADS
473 
474 	if( result == -1 )
475 	{
476 		pyesedb_error_raise(
477 		 error,
478 		 PyExc_IOError,
479 		 "%s: unable to determine size of name as UTF-8 string.",
480 		 function );
481 
482 		libcerror_error_free(
483 		 &error );
484 
485 		goto on_error;
486 	}
487 	else if( ( result == 0 )
488 	      || ( utf8_string_size == 0 ) )
489 	{
490 		Py_IncRef(
491 		 Py_None );
492 
493 		return( Py_None );
494 	}
495 	utf8_string = (char *) PyMem_Malloc(
496 	                        sizeof( char ) * utf8_string_size );
497 
498 	if( utf8_string == NULL )
499 	{
500 		PyErr_Format(
501 		 PyExc_MemoryError,
502 		 "%s: unable to create UTF-8 string.",
503 		 function );
504 
505 		goto on_error;
506 	}
507 	Py_BEGIN_ALLOW_THREADS
508 
509 	result = libesedb_column_get_utf8_name(
510 	          pyesedb_column->column,
511 	          (uint8_t *) utf8_string,
512 	          utf8_string_size,
513 	          &error );
514 
515 	Py_END_ALLOW_THREADS
516 
517 	if( result != 1 )
518 	{
519 		pyesedb_error_raise(
520 		 error,
521 		 PyExc_IOError,
522 		 "%s: unable to retrieve name as UTF-8 string.",
523 		 function );
524 
525 		libcerror_error_free(
526 		 &error );
527 
528 		goto on_error;
529 	}
530 	/* Pass the string length to PyUnicode_DecodeUTF8 otherwise it makes
531 	 * the end of string character is part of the string.
532 	 */
533 	string_object = PyUnicode_DecodeUTF8(
534 	                 utf8_string,
535 	                 (Py_ssize_t) utf8_string_size - 1,
536 	                 errors );
537 
538 	if( string_object == NULL )
539 	{
540 		PyErr_Format(
541 		 PyExc_IOError,
542 		 "%s: unable to convert UTF-8 string into Unicode object.",
543 		 function );
544 
545 		goto on_error;
546 	}
547 	PyMem_Free(
548 	 utf8_string );
549 
550 	return( string_object );
551 
552 on_error:
553 	if( utf8_string != NULL )
554 	{
555 		PyMem_Free(
556 		 utf8_string );
557 	}
558 	return( NULL );
559 }
560 
561