1 /*
2  * Python object wrapper of libcreg_file_t
3  *
4  * Copyright (C) 2013-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 <narrow_string.h>
24 #include <types.h>
25 
26 #if defined( HAVE_STDLIB_H ) || defined( HAVE_WINAPI )
27 #include <stdlib.h>
28 #endif
29 
30 #include "pycreg_codepage.h"
31 #include "pycreg_error.h"
32 #include "pycreg_file.h"
33 #include "pycreg_file_object_io_handle.h"
34 #include "pycreg_key.h"
35 #include "pycreg_libbfio.h"
36 #include "pycreg_libcerror.h"
37 #include "pycreg_libclocale.h"
38 #include "pycreg_libcreg.h"
39 #include "pycreg_python.h"
40 #include "pycreg_unused.h"
41 
42 #if !defined( LIBCREG_HAVE_BFIO )
43 
44 LIBCREG_EXTERN \
45 int libcreg_file_open_file_io_handle(
46      libcreg_file_t *file,
47      libbfio_handle_t *file_io_handle,
48      int access_flags,
49      libcreg_error_t **error );
50 
51 #endif /* !defined( LIBCREG_HAVE_BFIO ) */
52 
53 PyMethodDef pycreg_file_object_methods[] = {
54 
55 	{ "signal_abort",
56 	  (PyCFunction) pycreg_file_signal_abort,
57 	  METH_NOARGS,
58 	  "signal_abort() -> None\n"
59 	  "\n"
60 	  "Signals the file to abort the current activity." },
61 
62 	{ "open",
63 	  (PyCFunction) pycreg_file_open,
64 	  METH_VARARGS | METH_KEYWORDS,
65 	  "open(filename, mode='r') -> None\n"
66 	  "\n"
67 	  "Opens a file." },
68 
69 	{ "open_file_object",
70 	  (PyCFunction) pycreg_file_open_file_object,
71 	  METH_VARARGS | METH_KEYWORDS,
72 	  "open_file_object(file_object, mode='r') -> None\n"
73 	  "\n"
74 	  "Opens a file using a file-like object." },
75 
76 	{ "close",
77 	  (PyCFunction) pycreg_file_close,
78 	  METH_NOARGS,
79 	  "close() -> None\n"
80 	  "\n"
81 	  "Closes a file." },
82 
83 	{ "is_corrupted",
84 	  (PyCFunction) pycreg_file_is_corrupted,
85 	  METH_NOARGS,
86 	  "is_corrupted() -> Boolean\n"
87 	  "\n"
88 	  "Determines if the file is corrupted." },
89 
90 	{ "get_ascii_codepage",
91 	  (PyCFunction) pycreg_file_get_ascii_codepage,
92 	  METH_NOARGS,
93 	  "get_ascii_codepage() -> String\n"
94 	  "\n"
95 	  "Retrieves the codepage for ASCII strings used in the file." },
96 
97 	{ "set_ascii_codepage",
98 	  (PyCFunction) pycreg_file_set_ascii_codepage,
99 	  METH_VARARGS | METH_KEYWORDS,
100 	  "set_ascii_codepage(codepage) -> None\n"
101 	  "\n"
102 	  "Sets the codepage for ASCII strings used in the file.\n"
103 	  "Expects the codepage to be a string containing a Python codec definition." },
104 
105 	{ "get_format_version",
106 	  (PyCFunction) pycreg_file_get_format_version,
107 	  METH_NOARGS,
108 	  "get_format_version() -> Unicode string\n"
109 	  "\n"
110 	  "Retrieves the format version." },
111 
112 	{ "get_type",
113 	  (PyCFunction) pycreg_file_get_type,
114 	  METH_NOARGS,
115 	  "get_type() -> Integer\n"
116 	  "\n"
117 	  "Retrieves the type." },
118 
119 	{ "get_root_key",
120 	  (PyCFunction) pycreg_file_get_root_key,
121 	  METH_NOARGS,
122 	  "get_root_key() -> Object\n"
123 	  "\n"
124 	  "Retrieves the root key." },
125 
126 	{ "get_key_by_path",
127 	  (PyCFunction) pycreg_file_get_key_by_path,
128 	  METH_VARARGS | METH_KEYWORDS,
129 	  "get_key_by_path(path) -> Object or None\n"
130 	  "\n"
131 	  "Retrieves the key specified by the path." },
132 
133 	/* Sentinel */
134 	{ NULL, NULL, 0, NULL }
135 };
136 
137 PyGetSetDef pycreg_file_object_get_set_definitions[] = {
138 
139 	{ "corrupted",
140 	  (getter) pycreg_file_is_corrupted,
141 	  (setter) 0,
142 	  "Value to indicate the file is corrupted.",
143 	  NULL },
144 
145 	{ "ascii_codepage",
146 	  (getter) pycreg_file_get_ascii_codepage,
147 	  (setter) pycreg_file_set_ascii_codepage_setter,
148 	  "The codepage used for ASCII strings in the file.",
149 	  NULL },
150 
151 	{ "format_version",
152 	  (getter) pycreg_file_get_format_version,
153 	  (setter) 0,
154 	  "The format version.",
155 	  NULL },
156 
157 	{ "type",
158 	  (getter) pycreg_file_get_type,
159 	  (setter) 0,
160 	  "The type.",
161 	  NULL },
162 
163 	{ "root_key",
164 	  (getter) pycreg_file_get_root_key,
165 	  (setter) 0,
166 	  "The root key.",
167 	  NULL },
168 
169 	/* Sentinel */
170 	{ NULL, NULL, NULL, NULL, NULL }
171 };
172 
173 PyTypeObject pycreg_file_type_object = {
174 	PyVarObject_HEAD_INIT( NULL, 0 )
175 
176 	/* tp_name */
177 	"pycreg.file",
178 	/* tp_basicsize */
179 	sizeof( pycreg_file_t ),
180 	/* tp_itemsize */
181 	0,
182 	/* tp_dealloc */
183 	(destructor) pycreg_file_free,
184 	/* tp_print */
185 	0,
186 	/* tp_getattr */
187 	0,
188 	/* tp_setattr */
189 	0,
190 	/* tp_compare */
191 	0,
192 	/* tp_repr */
193 	0,
194 	/* tp_as_number */
195 	0,
196 	/* tp_as_sequence */
197 	0,
198 	/* tp_as_mapping */
199 	0,
200 	/* tp_hash */
201 	0,
202 	/* tp_call */
203 	0,
204 	/* tp_str */
205 	0,
206 	/* tp_getattro */
207 	0,
208 	/* tp_setattro */
209 	0,
210 	/* tp_as_buffer */
211 	0,
212 	/* tp_flags */
213 	Py_TPFLAGS_DEFAULT,
214 	/* tp_doc */
215 	"pycreg file object (wraps libcreg_file_t)",
216 	/* tp_traverse */
217 	0,
218 	/* tp_clear */
219 	0,
220 	/* tp_richcompare */
221 	0,
222 	/* tp_weaklistoffset */
223 	0,
224 	/* tp_iter */
225 	0,
226 	/* tp_iternext */
227 	0,
228 	/* tp_methods */
229 	pycreg_file_object_methods,
230 	/* tp_members */
231 	0,
232 	/* tp_getset */
233 	pycreg_file_object_get_set_definitions,
234 	/* tp_base */
235 	0,
236 	/* tp_dict */
237 	0,
238 	/* tp_descr_get */
239 	0,
240 	/* tp_descr_set */
241 	0,
242 	/* tp_dictoffset */
243 	0,
244 	/* tp_init */
245 	(initproc) pycreg_file_init,
246 	/* tp_alloc */
247 	0,
248 	/* tp_new */
249 	0,
250 	/* tp_free */
251 	0,
252 	/* tp_is_gc */
253 	0,
254 	/* tp_bases */
255 	NULL,
256 	/* tp_mro */
257 	NULL,
258 	/* tp_cache */
259 	NULL,
260 	/* tp_subclasses */
261 	NULL,
262 	/* tp_weaklist */
263 	NULL,
264 	/* tp_del */
265 	0
266 };
267 
268 /* Initializes a file object
269  * Returns 0 if successful or -1 on error
270  */
pycreg_file_init(pycreg_file_t * pycreg_file)271 int pycreg_file_init(
272      pycreg_file_t *pycreg_file )
273 {
274 	libcerror_error_t *error = NULL;
275 	static char *function    = "pycreg_file_init";
276 
277 	if( pycreg_file == NULL )
278 	{
279 		PyErr_Format(
280 		 PyExc_ValueError,
281 		 "%s: invalid file.",
282 		 function );
283 
284 		return( -1 );
285 	}
286 	/* Make sure libcreg file is set to NULL
287 	 */
288 	pycreg_file->file           = NULL;
289 	pycreg_file->file_io_handle = NULL;
290 
291 	if( libcreg_file_initialize(
292 	     &( pycreg_file->file ),
293 	     &error ) != 1 )
294 	{
295 		pycreg_error_raise(
296 		 error,
297 		 PyExc_MemoryError,
298 		 "%s: unable to initialize file.",
299 		 function );
300 
301 		libcerror_error_free(
302 		 &error );
303 
304 		return( -1 );
305 	}
306 	return( 0 );
307 }
308 
309 /* Frees a file object
310  */
pycreg_file_free(pycreg_file_t * pycreg_file)311 void pycreg_file_free(
312       pycreg_file_t *pycreg_file )
313 {
314 	struct _typeobject *ob_type = NULL;
315 	libcerror_error_t *error    = NULL;
316 	static char *function       = "pycreg_file_free";
317 	int result                  = 0;
318 
319 	if( pycreg_file == NULL )
320 	{
321 		PyErr_Format(
322 		 PyExc_ValueError,
323 		 "%s: invalid file.",
324 		 function );
325 
326 		return;
327 	}
328 	ob_type = Py_TYPE(
329 	           pycreg_file );
330 
331 	if( ob_type == NULL )
332 	{
333 		PyErr_Format(
334 		 PyExc_ValueError,
335 		 "%s: missing ob_type.",
336 		 function );
337 
338 		return;
339 	}
340 	if( ob_type->tp_free == NULL )
341 	{
342 		PyErr_Format(
343 		 PyExc_ValueError,
344 		 "%s: invalid ob_type - missing tp_free.",
345 		 function );
346 
347 		return;
348 	}
349 	if( pycreg_file->file != NULL )
350 	{
351 		Py_BEGIN_ALLOW_THREADS
352 
353 		result = libcreg_file_free(
354 		          &( pycreg_file->file ),
355 		          &error );
356 
357 		Py_END_ALLOW_THREADS
358 
359 		if( result != 1 )
360 		{
361 			pycreg_error_raise(
362 			 error,
363 			 PyExc_MemoryError,
364 			 "%s: unable to free libcreg file.",
365 			 function );
366 
367 			libcerror_error_free(
368 			 &error );
369 		}
370 	}
371 	ob_type->tp_free(
372 	 (PyObject*) pycreg_file );
373 }
374 
375 /* Signals the file to abort the current activity
376  * Returns a Python object if successful or NULL on error
377  */
pycreg_file_signal_abort(pycreg_file_t * pycreg_file,PyObject * arguments PYCREG_ATTRIBUTE_UNUSED)378 PyObject *pycreg_file_signal_abort(
379            pycreg_file_t *pycreg_file,
380            PyObject *arguments PYCREG_ATTRIBUTE_UNUSED )
381 {
382 	libcerror_error_t *error = NULL;
383 	static char *function    = "pycreg_file_signal_abort";
384 	int result               = 0;
385 
386 	PYCREG_UNREFERENCED_PARAMETER( arguments )
387 
388 	if( pycreg_file == NULL )
389 	{
390 		PyErr_Format(
391 		 PyExc_ValueError,
392 		 "%s: invalid file.",
393 		 function );
394 
395 		return( NULL );
396 	}
397 	Py_BEGIN_ALLOW_THREADS
398 
399 	result = libcreg_file_signal_abort(
400 	          pycreg_file->file,
401 	          &error );
402 
403 	Py_END_ALLOW_THREADS
404 
405 	if( result != 1 )
406 	{
407 		pycreg_error_raise(
408 		 error,
409 		 PyExc_IOError,
410 		 "%s: unable to signal abort.",
411 		 function );
412 
413 		libcerror_error_free(
414 		 &error );
415 
416 		return( NULL );
417 	}
418 	Py_IncRef(
419 	 Py_None );
420 
421 	return( Py_None );
422 }
423 
424 /* Opens a file
425  * Returns a Python object if successful or NULL on error
426  */
pycreg_file_open(pycreg_file_t * pycreg_file,PyObject * arguments,PyObject * keywords)427 PyObject *pycreg_file_open(
428            pycreg_file_t *pycreg_file,
429            PyObject *arguments,
430            PyObject *keywords )
431 {
432 	PyObject *string_object      = NULL;
433 	libcerror_error_t *error     = NULL;
434 	const char *filename_narrow  = NULL;
435 	static char *function        = "pycreg_file_open";
436 	static char *keyword_list[]  = { "filename", "mode", NULL };
437 	char *mode                   = NULL;
438 	int result                   = 0;
439 
440 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
441 	const wchar_t *filename_wide = NULL;
442 #else
443 	PyObject *utf8_string_object = NULL;
444 #endif
445 
446 	if( pycreg_file == NULL )
447 	{
448 		PyErr_Format(
449 		 PyExc_ValueError,
450 		 "%s: invalid file.",
451 		 function );
452 
453 		return( NULL );
454 	}
455 	/* Note that PyArg_ParseTupleAndKeywords with "s" will force Unicode strings to be converted to narrow character string.
456 	 * On Windows the narrow character strings contains an extended ASCII string with a codepage. Hence we get a conversion
457 	 * exception. This will also fail if the default encoding is not set correctly. We cannot use "u" here either since that
458 	 * does not allow us to pass non Unicode string objects and Python (at least 2.7) does not seems to automatically upcast them.
459 	 */
460 	if( PyArg_ParseTupleAndKeywords(
461 	     arguments,
462 	     keywords,
463 	     "O|s",
464 	     keyword_list,
465 	     &string_object,
466 	     &mode ) == 0 )
467 	{
468 		return( NULL );
469 	}
470 	if( ( mode != NULL )
471 	 && ( mode[ 0 ] != 'r' ) )
472 	{
473 		PyErr_Format(
474 		 PyExc_ValueError,
475 		 "%s: unsupported mode: %s.",
476 		 function,
477 		 mode );
478 
479 		return( NULL );
480 	}
481 	PyErr_Clear();
482 
483 	result = PyObject_IsInstance(
484 	          string_object,
485 	          (PyObject *) &PyUnicode_Type );
486 
487 	if( result == -1 )
488 	{
489 		pycreg_error_fetch_and_raise(
490 		 PyExc_RuntimeError,
491 		 "%s: unable to determine if string object is of type Unicode.",
492 		 function );
493 
494 		return( NULL );
495 	}
496 	else if( result != 0 )
497 	{
498 		PyErr_Clear();
499 
500 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
501 		filename_wide = (wchar_t *) PyUnicode_AsUnicode(
502 		                             string_object );
503 		Py_BEGIN_ALLOW_THREADS
504 
505 		result = libcreg_file_open_wide(
506 		          pycreg_file->file,
507 		          filename_wide,
508 		          LIBCREG_OPEN_READ,
509 		          &error );
510 
511 		Py_END_ALLOW_THREADS
512 #else
513 		utf8_string_object = PyUnicode_AsUTF8String(
514 		                      string_object );
515 
516 		if( utf8_string_object == NULL )
517 		{
518 			pycreg_error_fetch_and_raise(
519 			 PyExc_RuntimeError,
520 			 "%s: unable to convert Unicode string to UTF-8.",
521 			 function );
522 
523 			return( NULL );
524 		}
525 #if PY_MAJOR_VERSION >= 3
526 		filename_narrow = PyBytes_AsString(
527 		                   utf8_string_object );
528 #else
529 		filename_narrow = PyString_AsString(
530 		                   utf8_string_object );
531 #endif
532 		Py_BEGIN_ALLOW_THREADS
533 
534 		result = libcreg_file_open(
535 		          pycreg_file->file,
536 		          filename_narrow,
537 		          LIBCREG_OPEN_READ,
538 		          &error );
539 
540 		Py_END_ALLOW_THREADS
541 
542 		Py_DecRef(
543 		 utf8_string_object );
544 #endif
545 		if( result != 1 )
546 		{
547 			pycreg_error_raise(
548 			 error,
549 			 PyExc_IOError,
550 			 "%s: unable to open file.",
551 			 function );
552 
553 			libcerror_error_free(
554 			 &error );
555 
556 			return( NULL );
557 		}
558 		Py_IncRef(
559 		 Py_None );
560 
561 		return( Py_None );
562 	}
563 	PyErr_Clear();
564 
565 #if PY_MAJOR_VERSION >= 3
566 	result = PyObject_IsInstance(
567 	          string_object,
568 	          (PyObject *) &PyBytes_Type );
569 #else
570 	result = PyObject_IsInstance(
571 	          string_object,
572 	          (PyObject *) &PyString_Type );
573 #endif
574 	if( result == -1 )
575 	{
576 		pycreg_error_fetch_and_raise(
577 		 PyExc_RuntimeError,
578 		 "%s: unable to determine if string object is of type string.",
579 		 function );
580 
581 		return( NULL );
582 	}
583 	else if( result != 0 )
584 	{
585 		PyErr_Clear();
586 
587 #if PY_MAJOR_VERSION >= 3
588 		filename_narrow = PyBytes_AsString(
589 		                   string_object );
590 #else
591 		filename_narrow = PyString_AsString(
592 		                   string_object );
593 #endif
594 		Py_BEGIN_ALLOW_THREADS
595 
596 		result = libcreg_file_open(
597 		          pycreg_file->file,
598 		          filename_narrow,
599 		          LIBCREG_OPEN_READ,
600 		          &error );
601 
602 		Py_END_ALLOW_THREADS
603 
604 		if( result != 1 )
605 		{
606 			pycreg_error_raise(
607 			 error,
608 			 PyExc_IOError,
609 			 "%s: unable to open file.",
610 			 function );
611 
612 			libcerror_error_free(
613 			 &error );
614 
615 			return( NULL );
616 		}
617 		Py_IncRef(
618 		 Py_None );
619 
620 		return( Py_None );
621 	}
622 	PyErr_Format(
623 	 PyExc_TypeError,
624 	 "%s: unsupported string object type.",
625 	 function );
626 
627 	return( NULL );
628 }
629 
630 /* Opens a file using a file-like object
631  * Returns a Python object if successful or NULL on error
632  */
pycreg_file_open_file_object(pycreg_file_t * pycreg_file,PyObject * arguments,PyObject * keywords)633 PyObject *pycreg_file_open_file_object(
634            pycreg_file_t *pycreg_file,
635            PyObject *arguments,
636            PyObject *keywords )
637 {
638 	PyObject *file_object       = NULL;
639 	libcerror_error_t *error    = NULL;
640 	static char *function       = "pycreg_file_open_file_object";
641 	static char *keyword_list[] = { "file_object", "mode", NULL };
642 	char *mode                  = NULL;
643 	int result                  = 0;
644 
645 	if( pycreg_file == NULL )
646 	{
647 		PyErr_Format(
648 		 PyExc_ValueError,
649 		 "%s: invalid file.",
650 		 function );
651 
652 		return( NULL );
653 	}
654 	if( PyArg_ParseTupleAndKeywords(
655 	     arguments,
656 	     keywords,
657 	     "O|s",
658 	     keyword_list,
659 	     &file_object,
660 	     &mode ) == 0 )
661 	{
662 		return( NULL );
663 	}
664 	if( ( mode != NULL )
665 	 && ( mode[ 0 ] != 'r' ) )
666 	{
667 		PyErr_Format(
668 		 PyExc_ValueError,
669 		 "%s: unsupported mode: %s.",
670 		 function,
671 		 mode );
672 
673 		return( NULL );
674 	}
675 	PyErr_Clear();
676 
677 	result = PyObject_HasAttrString(
678 	          file_object,
679 	          "read" );
680 
681 	if( result != 1 )
682 	{
683 		PyErr_Format(
684 		 PyExc_TypeError,
685 		 "%s: unsupported file object - missing read attribute.",
686 		 function );
687 
688 		return( NULL );
689 	}
690 	PyErr_Clear();
691 
692 	result = PyObject_HasAttrString(
693 	          file_object,
694 	          "seek" );
695 
696 	if( result != 1 )
697 	{
698 		PyErr_Format(
699 		 PyExc_TypeError,
700 		 "%s: unsupported file object - missing seek attribute.",
701 		 function );
702 
703 		return( NULL );
704 	}
705 	if( pycreg_file->file_io_handle != NULL )
706 	{
707 		pycreg_error_raise(
708 		 error,
709 		 PyExc_IOError,
710 		 "%s: invalid file - file IO handle already set.",
711 		 function );
712 
713 		goto on_error;
714 	}
715 	if( pycreg_file_object_initialize(
716 	     &( pycreg_file->file_io_handle ),
717 	     file_object,
718 	     &error ) != 1 )
719 	{
720 		pycreg_error_raise(
721 		 error,
722 		 PyExc_MemoryError,
723 		 "%s: unable to initialize file IO handle.",
724 		 function );
725 
726 		libcerror_error_free(
727 		 &error );
728 
729 		goto on_error;
730 	}
731 	Py_BEGIN_ALLOW_THREADS
732 
733 	result = libcreg_file_open_file_io_handle(
734 	          pycreg_file->file,
735 	          pycreg_file->file_io_handle,
736 	          LIBCREG_OPEN_READ,
737 	          &error );
738 
739 	Py_END_ALLOW_THREADS
740 
741 	if( result != 1 )
742 	{
743 		pycreg_error_raise(
744 		 error,
745 		 PyExc_IOError,
746 		 "%s: unable to open file.",
747 		 function );
748 
749 		libcerror_error_free(
750 		 &error );
751 
752 		goto on_error;
753 	}
754 	Py_IncRef(
755 	 Py_None );
756 
757 	return( Py_None );
758 
759 on_error:
760 	if( pycreg_file->file_io_handle != NULL )
761 	{
762 		libbfio_handle_free(
763 		 &( pycreg_file->file_io_handle ),
764 		 NULL );
765 	}
766 	return( NULL );
767 }
768 
769 /* Closes a file
770  * Returns a Python object if successful or NULL on error
771  */
pycreg_file_close(pycreg_file_t * pycreg_file,PyObject * arguments PYCREG_ATTRIBUTE_UNUSED)772 PyObject *pycreg_file_close(
773            pycreg_file_t *pycreg_file,
774            PyObject *arguments PYCREG_ATTRIBUTE_UNUSED )
775 {
776 	libcerror_error_t *error = NULL;
777 	static char *function    = "pycreg_file_close";
778 	int result               = 0;
779 
780 	PYCREG_UNREFERENCED_PARAMETER( arguments )
781 
782 	if( pycreg_file == NULL )
783 	{
784 		PyErr_Format(
785 		 PyExc_ValueError,
786 		 "%s: invalid file.",
787 		 function );
788 
789 		return( NULL );
790 	}
791 	Py_BEGIN_ALLOW_THREADS
792 
793 	result = libcreg_file_close(
794 	          pycreg_file->file,
795 	          &error );
796 
797 	Py_END_ALLOW_THREADS
798 
799 	if( result != 0 )
800 	{
801 		pycreg_error_raise(
802 		 error,
803 		 PyExc_IOError,
804 		 "%s: unable to close file.",
805 		 function );
806 
807 		libcerror_error_free(
808 		 &error );
809 
810 		return( NULL );
811 	}
812 	if( pycreg_file->file_io_handle != NULL )
813 	{
814 		Py_BEGIN_ALLOW_THREADS
815 
816 		result = libbfio_handle_free(
817 		          &( pycreg_file->file_io_handle ),
818 		          &error );
819 
820 		Py_END_ALLOW_THREADS
821 
822 		if( result != 1 )
823 		{
824 			pycreg_error_raise(
825 			 error,
826 			 PyExc_MemoryError,
827 			 "%s: unable to free libbfio file IO handle.",
828 			 function );
829 
830 			libcerror_error_free(
831 			 &error );
832 
833 			return( NULL );
834 		}
835 	}
836 	Py_IncRef(
837 	 Py_None );
838 
839 	return( Py_None );
840 }
841 
842 /* Determines if the file is corrupted
843  * Returns a Python object if successful or NULL on error
844  */
pycreg_file_is_corrupted(pycreg_file_t * pycreg_file,PyObject * arguments PYCREG_ATTRIBUTE_UNUSED)845 PyObject *pycreg_file_is_corrupted(
846            pycreg_file_t *pycreg_file,
847            PyObject *arguments PYCREG_ATTRIBUTE_UNUSED )
848 {
849 	libcerror_error_t *error = NULL;
850 	static char *function    = "pycreg_file_is_corrupted";
851 	int result               = 0;
852 
853 	PYCREG_UNREFERENCED_PARAMETER( arguments )
854 
855 	if( pycreg_file == NULL )
856 	{
857 		PyErr_Format(
858 		 PyExc_ValueError,
859 		 "%s: invalid file.",
860 		 function );
861 
862 		return( NULL );
863 	}
864 	Py_BEGIN_ALLOW_THREADS
865 
866 	result = libcreg_file_is_corrupted(
867 	          pycreg_file->file,
868 	          &error );
869 
870 	Py_END_ALLOW_THREADS
871 
872 	if( result == -1 )
873 	{
874 		pycreg_error_raise(
875 		 error,
876 		 PyExc_IOError,
877 		 "%s: unable to determine if file is corrupted.",
878 		 function );
879 
880 		libcerror_error_free(
881 		 &error );
882 
883 		return( NULL );
884 	}
885 	if( result != 0 )
886 	{
887 		Py_IncRef(
888 		 (PyObject *) Py_True );
889 
890 		return( Py_True );
891 	}
892 	Py_IncRef(
893 	 (PyObject *) Py_False );
894 
895 	return( Py_False );
896 }
897 
898 /* Retrieves the codepage used for ASCII strings in the file
899  * Returns a Python object if successful or NULL on error
900  */
pycreg_file_get_ascii_codepage(pycreg_file_t * pycreg_file,PyObject * arguments PYCREG_ATTRIBUTE_UNUSED)901 PyObject *pycreg_file_get_ascii_codepage(
902            pycreg_file_t *pycreg_file,
903            PyObject *arguments PYCREG_ATTRIBUTE_UNUSED )
904 {
905 	PyObject *string_object     = NULL;
906 	libcerror_error_t *error    = NULL;
907 	const char *codepage_string = NULL;
908 	static char *function       = "pycreg_file_get_ascii_codepage";
909 	int ascii_codepage          = 0;
910 	int result                  = 0;
911 
912 	PYCREG_UNREFERENCED_PARAMETER( arguments )
913 
914 	if( pycreg_file == NULL )
915 	{
916 		PyErr_Format(
917 		 PyExc_ValueError,
918 		 "%s: invalid file.",
919 		 function );
920 
921 		return( NULL );
922 	}
923 	Py_BEGIN_ALLOW_THREADS
924 
925 	result = libcreg_file_get_ascii_codepage(
926 	          pycreg_file->file,
927 	          &ascii_codepage,
928 	          &error );
929 
930 	Py_END_ALLOW_THREADS
931 
932 	if( result != 1 )
933 	{
934 		pycreg_error_raise(
935 		 error,
936 		 PyExc_IOError,
937 		 "%s: unable to retrieve ASCII codepage.",
938 		 function );
939 
940 		libcerror_error_free(
941 		 &error );
942 
943 		return( NULL );
944 	}
945 	codepage_string = pycreg_codepage_to_string(
946 	                   ascii_codepage );
947 
948 	if( codepage_string == NULL )
949 	{
950 		PyErr_Format(
951 		 PyExc_ValueError,
952 		 "%s: unsupported ASCII codepage: %d.",
953 		 function,
954 		 ascii_codepage );
955 
956 		return( NULL );
957 	}
958 #if PY_MAJOR_VERSION >= 3
959 	string_object = PyBytes_FromString(
960 	                 codepage_string );
961 #else
962 	string_object = PyString_FromString(
963 	                 codepage_string );
964 #endif
965 	if( string_object == NULL )
966 	{
967 		PyErr_Format(
968 		 PyExc_IOError,
969 		 "%s: unable to convert codepage string into string object.",
970 		 function );
971 
972 		return( NULL );
973 	}
974 	return( string_object );
975 }
976 
977 /* Sets the codepage used for ASCII strings in the file
978  * Returns 1 if successful or -1 on error
979  */
pycreg_file_set_ascii_codepage_from_string(pycreg_file_t * pycreg_file,const char * codepage_string)980 int pycreg_file_set_ascii_codepage_from_string(
981      pycreg_file_t *pycreg_file,
982      const char *codepage_string )
983 {
984 	libcerror_error_t *error      = NULL;
985 	static char *function         = "pycreg_file_set_ascii_codepage_from_string";
986 	size_t codepage_string_length = 0;
987 	uint32_t feature_flags        = 0;
988 	int ascii_codepage            = 0;
989 	int result                    = 0;
990 
991 	if( pycreg_file == NULL )
992 	{
993 		PyErr_Format(
994 		 PyExc_ValueError,
995 		 "%s: invalid file.",
996 		 function );
997 
998 		return( -1 );
999 	}
1000 	if( codepage_string == NULL )
1001 	{
1002 		PyErr_Format(
1003 		 PyExc_ValueError,
1004 		 "%s: invalid codepage string.",
1005 		 function );
1006 
1007 		return( -1 );
1008 	}
1009 	codepage_string_length = narrow_string_length(
1010 	                          codepage_string );
1011 
1012 	feature_flags = LIBCLOCALE_CODEPAGE_FEATURE_FLAG_HAVE_WINDOWS;
1013 
1014 	if( libclocale_codepage_copy_from_string(
1015 	     &ascii_codepage,
1016 	     codepage_string,
1017 	     codepage_string_length,
1018 	     feature_flags,
1019 	     &error ) != 1 )
1020 	{
1021 		pycreg_error_raise(
1022 		 error,
1023 		 PyExc_RuntimeError,
1024 		 "%s: unable to determine ASCII codepage.",
1025 		 function );
1026 
1027 		libcerror_error_free(
1028 		 &error );
1029 
1030 		return( -1 );
1031 	}
1032 	Py_BEGIN_ALLOW_THREADS
1033 
1034 	result = libcreg_file_set_ascii_codepage(
1035 	          pycreg_file->file,
1036 	          ascii_codepage,
1037 	          &error );
1038 
1039 	Py_END_ALLOW_THREADS
1040 
1041 	if( result != 1 )
1042 	{
1043 		pycreg_error_raise(
1044 		 error,
1045 		 PyExc_IOError,
1046 		 "%s: unable to set ASCII codepage.",
1047 		 function );
1048 
1049 		libcerror_error_free(
1050 		 &error );
1051 
1052 		return( -1 );
1053 	}
1054 	return( 1 );
1055 }
1056 
1057 /* Sets the codepage used for ASCII strings in the file
1058  * Returns a Python object if successful or NULL on error
1059  */
pycreg_file_set_ascii_codepage(pycreg_file_t * pycreg_file,PyObject * arguments,PyObject * keywords)1060 PyObject *pycreg_file_set_ascii_codepage(
1061            pycreg_file_t *pycreg_file,
1062            PyObject *arguments,
1063            PyObject *keywords )
1064 {
1065 	char *codepage_string       = NULL;
1066 	static char *keyword_list[] = { "codepage", NULL };
1067 	int result                  = 0;
1068 
1069 	if( PyArg_ParseTupleAndKeywords(
1070 	     arguments,
1071 	     keywords,
1072 	     "s",
1073 	     keyword_list,
1074 	     &codepage_string ) == 0 )
1075 	{
1076 		return( NULL );
1077 	}
1078 	result = pycreg_file_set_ascii_codepage_from_string(
1079 	          pycreg_file,
1080 	          codepage_string );
1081 
1082 	if( result != 1 )
1083 	{
1084 		return( NULL );
1085 	}
1086 	Py_IncRef(
1087 	 Py_None );
1088 
1089 	return( Py_None );
1090 }
1091 
1092 /* Sets the codepage used for ASCII strings in the file
1093  * Returns a Python object if successful or NULL on error
1094  */
pycreg_file_set_ascii_codepage_setter(pycreg_file_t * pycreg_file,PyObject * string_object,void * closure PYCREG_ATTRIBUTE_UNUSED)1095 int pycreg_file_set_ascii_codepage_setter(
1096      pycreg_file_t *pycreg_file,
1097      PyObject *string_object,
1098      void *closure PYCREG_ATTRIBUTE_UNUSED )
1099 {
1100 	PyObject *utf8_string_object = NULL;
1101 	char *codepage_string        = NULL;
1102 	static char *function        = "pycreg_file_set_ascii_codepage_setter";
1103 	int result                   = 0;
1104 
1105 	PYCREG_UNREFERENCED_PARAMETER( closure )
1106 
1107 	PyErr_Clear();
1108 
1109 	result = PyObject_IsInstance(
1110 	          string_object,
1111 	          (PyObject *) &PyUnicode_Type );
1112 
1113 	if( result == -1 )
1114 	{
1115 		pycreg_error_fetch_and_raise(
1116 		 PyExc_RuntimeError,
1117 		 "%s: unable to determine if string object is of type Unicode.",
1118 		 function );
1119 
1120 		return( -1 );
1121 	}
1122 	else if( result != 0 )
1123 	{
1124 		/* The codepage string should only contain ASCII characters.
1125 		 */
1126 		utf8_string_object = PyUnicode_AsUTF8String(
1127 		                      string_object );
1128 
1129 		if( utf8_string_object == NULL )
1130 		{
1131 			pycreg_error_fetch_and_raise(
1132 			 PyExc_RuntimeError,
1133 			 "%s: unable to convert Unicode string to UTF-8.",
1134 			 function );
1135 
1136 			return( -1 );
1137 		}
1138 #if PY_MAJOR_VERSION >= 3
1139 		codepage_string = PyBytes_AsString(
1140 		                   utf8_string_object );
1141 #else
1142 		codepage_string = PyString_AsString(
1143 		                   utf8_string_object );
1144 #endif
1145 		if( codepage_string == NULL )
1146 		{
1147 			return( -1 );
1148 		}
1149 		result = pycreg_file_set_ascii_codepage_from_string(
1150 		          pycreg_file,
1151 		          codepage_string );
1152 
1153 		if( result != 1 )
1154 		{
1155 			return( -1 );
1156 		}
1157 		return( 0 );
1158 	}
1159 	PyErr_Clear();
1160 
1161 #if PY_MAJOR_VERSION >= 3
1162 	result = PyObject_IsInstance(
1163 	          string_object,
1164 	          (PyObject *) &PyBytes_Type );
1165 #else
1166 	result = PyObject_IsInstance(
1167 	          string_object,
1168 	          (PyObject *) &PyString_Type );
1169 #endif
1170 	if( result == -1 )
1171 	{
1172 		pycreg_error_fetch_and_raise(
1173 		 PyExc_RuntimeError,
1174 		 "%s: unable to determine if string object is of type string.",
1175 		 function );
1176 
1177 		return( -1 );
1178 	}
1179 	else if( result != 0 )
1180 	{
1181 #if PY_MAJOR_VERSION >= 3
1182 		codepage_string = PyBytes_AsString(
1183 		                   string_object );
1184 #else
1185 		codepage_string = PyString_AsString(
1186 		                   string_object );
1187 #endif
1188 		if( codepage_string == NULL )
1189 		{
1190 			return( -1 );
1191 		}
1192 		result = pycreg_file_set_ascii_codepage_from_string(
1193 		          pycreg_file,
1194 		          codepage_string );
1195 
1196 		if( result != 1 )
1197 		{
1198 			return( -1 );
1199 		}
1200 		return( 0 );
1201 	}
1202 	PyErr_Format(
1203 	 PyExc_TypeError,
1204 	 "%s: unsupported string object type.",
1205 	 function );
1206 
1207 	return( -1 );
1208 }
1209 
1210 /* Retrieves the format version
1211  * Returns a Python object if successful or NULL on error
1212  */
pycreg_file_get_format_version(pycreg_file_t * pycreg_file,PyObject * arguments PYCREG_ATTRIBUTE_UNUSED)1213 PyObject *pycreg_file_get_format_version(
1214            pycreg_file_t *pycreg_file,
1215            PyObject *arguments PYCREG_ATTRIBUTE_UNUSED )
1216 {
1217 	char utf8_string[ 4 ];
1218 
1219 	PyObject *string_object  = NULL;
1220 	libcerror_error_t *error = NULL;
1221 	const char *errors       = NULL;
1222 	static char *function    = "pycreg_file_get_format_version";
1223 	uint16_t major_version   = 0;
1224 	uint16_t minor_version   = 0;
1225 	int result               = 0;
1226 
1227 	PYCREG_UNREFERENCED_PARAMETER( arguments )
1228 
1229 	if( pycreg_file == NULL )
1230 	{
1231 		PyErr_Format(
1232 		 PyExc_ValueError,
1233 		 "%s: invalid file.",
1234 		 function );
1235 
1236 		return( NULL );
1237 	}
1238 	Py_BEGIN_ALLOW_THREADS
1239 
1240 	result = libcreg_file_get_format_version(
1241 	          pycreg_file->file,
1242 	          &major_version,
1243 	          &minor_version,
1244 	          &error );
1245 
1246 	Py_END_ALLOW_THREADS
1247 
1248 	if( result != 1 )
1249 	{
1250 		pycreg_error_raise(
1251 		 error,
1252 		 PyExc_IOError,
1253 		 "%s: unable to retrieve format version.",
1254 		 function );
1255 
1256 		libcerror_error_free(
1257 		 &error );
1258 
1259 		return( NULL );
1260 	}
1261 	if( major_version > 9 )
1262 	{
1263 		PyErr_Format(
1264 		 PyExc_ValueError,
1265 		 "%s: major version out of bounds.",
1266 		 function );
1267 
1268 		return( NULL );
1269 	}
1270 	if( minor_version > 9 )
1271 	{
1272 		PyErr_Format(
1273 		 PyExc_ValueError,
1274 		 "%s: minor version out of bounds.",
1275 		 function );
1276 
1277 		return( NULL );
1278 	}
1279 	utf8_string[ 0 ] = '0' + (char) major_version;
1280 	utf8_string[ 1 ] = '.';
1281 	utf8_string[ 2 ] = '0' + (char) minor_version;
1282 	utf8_string[ 3 ] = 0;
1283 
1284 	/* Pass the string length to PyUnicode_DecodeUTF8 otherwise it makes
1285 	 * the end of string character is part of the string.
1286 	 */
1287 	string_object = PyUnicode_DecodeUTF8(
1288 	                 utf8_string,
1289 	                 (Py_ssize_t) 3,
1290 	                 errors );
1291 
1292 	if( string_object == NULL )
1293 	{
1294 		PyErr_Format(
1295 		 PyExc_IOError,
1296 		 "%s: unable to convert UTF-8 string into Unicode object.",
1297 		 function );
1298 
1299 		return( NULL );
1300 	}
1301 	return( string_object );
1302 }
1303 
1304 /* Retrieves the type
1305  * Returns a Python object if successful or NULL on error
1306  */
pycreg_file_get_type(pycreg_file_t * pycreg_file,PyObject * arguments PYCREG_ATTRIBUTE_UNUSED)1307 PyObject *pycreg_file_get_type(
1308            pycreg_file_t *pycreg_file,
1309            PyObject *arguments PYCREG_ATTRIBUTE_UNUSED )
1310 {
1311 	PyObject *integer_object = NULL;
1312 	libcerror_error_t *error = NULL;
1313 	static char *function    = "pycreg_file_get_type";
1314 	uint32_t value_32bit     = 0;
1315 	int result               = 0;
1316 
1317 	PYCREG_UNREFERENCED_PARAMETER( arguments )
1318 
1319 	if( pycreg_file == NULL )
1320 	{
1321 		PyErr_Format(
1322 		 PyExc_ValueError,
1323 		 "%s: invalid file.",
1324 		 function );
1325 
1326 		return( NULL );
1327 	}
1328 	Py_BEGIN_ALLOW_THREADS
1329 
1330 	result = libcreg_file_get_type(
1331 	          pycreg_file->file,
1332 	          &value_32bit,
1333 	          &error );
1334 
1335 	Py_END_ALLOW_THREADS
1336 
1337 	if( result != 1 )
1338 	{
1339 		pycreg_error_raise(
1340 		 error,
1341 		 PyExc_IOError,
1342 		 "%s: unable to retrieve type.",
1343 		 function );
1344 
1345 		libcerror_error_free(
1346 		 &error );
1347 
1348 		return( NULL );
1349 	}
1350 	integer_object = PyLong_FromUnsignedLong(
1351 	                  (unsigned long) value_32bit );
1352 
1353 	return( integer_object );
1354 }
1355 
1356 /* Retrieves the root key
1357  * Returns a Python object if successful or NULL on error
1358  */
pycreg_file_get_root_key(pycreg_file_t * pycreg_file,PyObject * arguments PYCREG_ATTRIBUTE_UNUSED)1359 PyObject *pycreg_file_get_root_key(
1360            pycreg_file_t *pycreg_file,
1361            PyObject *arguments PYCREG_ATTRIBUTE_UNUSED )
1362 {
1363 	PyObject *key_object     = NULL;
1364 	libcerror_error_t *error = NULL;
1365 	libcreg_key_t *root_key  = NULL;
1366 	static char *function    = "pycreg_file_get_root_key";
1367 	int result               = 0;
1368 
1369 	PYCREG_UNREFERENCED_PARAMETER( arguments )
1370 
1371 	if( pycreg_file == NULL )
1372 	{
1373 		PyErr_Format(
1374 		 PyExc_ValueError,
1375 		 "%s: invalid file.",
1376 		 function );
1377 
1378 		return( NULL );
1379 	}
1380 	Py_BEGIN_ALLOW_THREADS
1381 
1382 	result = libcreg_file_get_root_key(
1383 	          pycreg_file->file,
1384 	          &root_key,
1385 	          &error );
1386 
1387 	Py_END_ALLOW_THREADS
1388 
1389 	if( result == -1 )
1390 	{
1391 		pycreg_error_raise(
1392 		 error,
1393 		 PyExc_IOError,
1394 		 "%s: unable to retrieve root key.",
1395 		 function );
1396 
1397 		libcerror_error_free(
1398 		 &error );
1399 
1400 		goto on_error;
1401 	}
1402 	else if( result == 0 )
1403 	{
1404 		Py_IncRef(
1405 		 Py_None );
1406 
1407 		return( Py_None );
1408 	}
1409 	key_object = pycreg_key_new(
1410 	              root_key,
1411 	              (PyObject *) pycreg_file );
1412 
1413 	if( key_object == NULL )
1414 	{
1415 		PyErr_Format(
1416 		 PyExc_MemoryError,
1417 		 "%s: unable to create root key object.",
1418 		 function );
1419 
1420 		goto on_error;
1421 	}
1422 	return( key_object );
1423 
1424 on_error:
1425 	if( root_key != NULL )
1426 	{
1427 		libcreg_key_free(
1428 		 &root_key,
1429 		 NULL );
1430 	}
1431 	return( NULL );
1432 }
1433 
1434 /* Retrieves the key specified by the path
1435  * Returns a Python object if successful or NULL on error
1436  */
pycreg_file_get_key_by_path(pycreg_file_t * pycreg_file,PyObject * arguments,PyObject * keywords)1437 PyObject *pycreg_file_get_key_by_path(
1438            pycreg_file_t *pycreg_file,
1439            PyObject *arguments,
1440            PyObject *keywords )
1441 {
1442 	PyObject *key_object        = NULL;
1443 	libcerror_error_t *error    = NULL;
1444 	libcreg_key_t *key          = NULL;
1445 	static char *function       = "pycreg_file_get_key_by_path";
1446 	static char *keyword_list[] = { "path", NULL };
1447 	char *utf8_path             = NULL;
1448 	size_t utf8_path_length     = 0;
1449 	int result                  = 0;
1450 
1451 	if( pycreg_file == NULL )
1452 	{
1453 		PyErr_Format(
1454 		 PyExc_ValueError,
1455 		 "%s: invalid file.",
1456 		 function );
1457 
1458 		return( NULL );
1459 	}
1460 	if( PyArg_ParseTupleAndKeywords(
1461 	     arguments,
1462 	     keywords,
1463 	     "s",
1464 	     keyword_list,
1465 	     &utf8_path ) == 0 )
1466 	{
1467 		goto on_error;
1468 	}
1469 	utf8_path_length = narrow_string_length(
1470 	                    utf8_path );
1471 
1472 	Py_BEGIN_ALLOW_THREADS
1473 
1474 	result = libcreg_file_get_key_by_utf8_path(
1475 	          pycreg_file->file,
1476 	          (uint8_t *) utf8_path,
1477 	          utf8_path_length,
1478 	          &key,
1479 	          &error );
1480 
1481 	Py_END_ALLOW_THREADS
1482 
1483 	if( result == -1 )
1484 	{
1485 		pycreg_error_raise(
1486 		 error,
1487 		 PyExc_IOError,
1488 		 "%s: unable to retrieve key.",
1489 		 function );
1490 
1491 		libcerror_error_free(
1492 		 &error );
1493 
1494 		goto on_error;
1495 	}
1496 	else if( result == 0 )
1497 	{
1498 		Py_IncRef(
1499 		 Py_None );
1500 
1501 		return( Py_None );
1502 	}
1503 	key_object = pycreg_key_new(
1504 	              key,
1505 	              (PyObject *) pycreg_file );
1506 
1507 	if( key_object == NULL )
1508 	{
1509 		PyErr_Format(
1510 		 PyExc_MemoryError,
1511 		 "%s: unable to create key object.",
1512 		 function );
1513 
1514 		goto on_error;
1515 	}
1516 	return( key_object );
1517 
1518 on_error:
1519 	if( key != NULL )
1520 	{
1521 		libcreg_key_free(
1522 		 &key,
1523 		 NULL );
1524 	}
1525 	return( NULL );
1526 }
1527 
1528