1 /** @file
2 Efi Compressor
3 
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <Python.h>
10 #include <Decompress.h>
11 
12 /*
13  UefiDecompress(data_buffer, size, original_size)
14 */
15 STATIC
16 PyObject*
UefiDecompress(PyObject * Self,PyObject * Args)17 UefiDecompress(
18   PyObject    *Self,
19   PyObject    *Args
20   )
21 {
22   PyObject      *SrcData;
23   UINT32        SrcDataSize;
24   UINT32        DstDataSize;
25   UINTN         Status;
26   UINT8         *SrcBuf;
27   UINT8         *DstBuf;
28   UINT8         *TmpBuf;
29   Py_ssize_t    SegNum;
30   Py_ssize_t    Index;
31 
32   Status = PyArg_ParseTuple(
33             Args,
34             "Oi",
35             &SrcData,
36             &SrcDataSize
37             );
38   if (Status == 0) {
39     return NULL;
40   }
41 
42   if (SrcData->ob_type->tp_as_buffer == NULL
43       || SrcData->ob_type->tp_as_buffer->bf_getreadbuffer == NULL
44       || SrcData->ob_type->tp_as_buffer->bf_getsegcount == NULL) {
45     PyErr_SetString(PyExc_Exception, "First argument is not a buffer\n");
46     return NULL;
47   }
48 
49   // Because some Python objects which support "buffer" protocol have more than one
50   // memory segment, we have to copy them into a contiguous memory.
51   SrcBuf = PyMem_Malloc(SrcDataSize);
52   if (SrcBuf == NULL) {
53     PyErr_SetString(PyExc_Exception, "Not enough memory\n");
54     goto ERROR;
55   }
56 
57   SegNum = SrcData->ob_type->tp_as_buffer->bf_getsegcount((PyObject *)SrcData, NULL);
58   TmpBuf = SrcBuf;
59   for (Index = 0; Index < SegNum; ++Index) {
60     VOID *BufSeg;
61     Py_ssize_t Len;
62 
63     Len = SrcData->ob_type->tp_as_buffer->bf_getreadbuffer((PyObject *)SrcData, Index, &BufSeg);
64     if (Len < 0) {
65       PyErr_SetString(PyExc_Exception, "Buffer segment is not available\n");
66       goto ERROR;
67     }
68     memcpy(TmpBuf, BufSeg, Len);
69     TmpBuf += Len;
70   }
71 
72   Status = Extract((VOID *)SrcBuf, SrcDataSize, (VOID **)&DstBuf, &DstDataSize, 1);
73   if (Status != EFI_SUCCESS) {
74     PyErr_SetString(PyExc_Exception, "Failed to decompress\n");
75     goto ERROR;
76   }
77 
78   return PyBuffer_FromMemory(DstBuf, (Py_ssize_t)DstDataSize);
79 
80 ERROR:
81   if (SrcBuf != NULL) {
82     free(SrcBuf);
83   }
84 
85   if (DstBuf != NULL) {
86     free(DstBuf);
87   }
88   return NULL;
89 }
90 
91 
92 STATIC
93 PyObject*
FrameworkDecompress(PyObject * Self,PyObject * Args)94 FrameworkDecompress(
95   PyObject    *Self,
96   PyObject    *Args
97   )
98 {
99   PyObject      *SrcData;
100   UINT32        SrcDataSize;
101   UINT32        DstDataSize;
102   UINTN         Status;
103   UINT8         *SrcBuf;
104   UINT8         *DstBuf;
105   UINT8         *TmpBuf;
106   Py_ssize_t    SegNum;
107   Py_ssize_t    Index;
108 
109   Status = PyArg_ParseTuple(
110             Args,
111             "Oi",
112             &SrcData,
113             &SrcDataSize
114             );
115   if (Status == 0) {
116     return NULL;
117   }
118 
119   if (SrcData->ob_type->tp_as_buffer == NULL
120       || SrcData->ob_type->tp_as_buffer->bf_getreadbuffer == NULL
121       || SrcData->ob_type->tp_as_buffer->bf_getsegcount == NULL) {
122     PyErr_SetString(PyExc_Exception, "First argument is not a buffer\n");
123     return NULL;
124   }
125 
126   // Because some Python objects which support "buffer" protocol have more than one
127   // memory segment, we have to copy them into a contiguous memory.
128   SrcBuf = PyMem_Malloc(SrcDataSize);
129   if (SrcBuf == NULL) {
130     PyErr_SetString(PyExc_Exception, "Not enough memory\n");
131     goto ERROR;
132   }
133 
134   SegNum = SrcData->ob_type->tp_as_buffer->bf_getsegcount((PyObject *)SrcData, NULL);
135   TmpBuf = SrcBuf;
136   for (Index = 0; Index < SegNum; ++Index) {
137     VOID *BufSeg;
138     Py_ssize_t Len;
139 
140     Len = SrcData->ob_type->tp_as_buffer->bf_getreadbuffer((PyObject *)SrcData, Index, &BufSeg);
141     if (Len < 0) {
142       PyErr_SetString(PyExc_Exception, "Buffer segment is not available\n");
143       goto ERROR;
144     }
145     memcpy(TmpBuf, BufSeg, Len);
146     TmpBuf += Len;
147   }
148 
149   Status = Extract((VOID *)SrcBuf, SrcDataSize, (VOID **)&DstBuf, &DstDataSize, 2);
150   if (Status != EFI_SUCCESS) {
151     PyErr_SetString(PyExc_Exception, "Failed to decompress\n");
152     goto ERROR;
153   }
154 
155   return PyString_FromStringAndSize((CONST INT8*)DstBuf, (Py_ssize_t)DstDataSize);
156 
157 ERROR:
158   if (SrcBuf != NULL) {
159     free(SrcBuf);
160   }
161 
162   if (DstBuf != NULL) {
163     free(DstBuf);
164   }
165   return NULL;
166 }
167 
168 
169 STATIC
170 PyObject*
UefiCompress(PyObject * Self,PyObject * Args)171 UefiCompress(
172   PyObject    *Self,
173   PyObject    *Args
174   )
175 {
176   return NULL;
177 }
178 
179 
180 STATIC
181 PyObject*
FrameworkCompress(PyObject * Self,PyObject * Args)182 FrameworkCompress(
183   PyObject    *Self,
184   PyObject    *Args
185   )
186 {
187   return NULL;
188 }
189 
190 STATIC INT8 DecompressDocs[] = "Decompress(): Decompress data using UEFI standard algorithm\n";
191 STATIC INT8 CompressDocs[] = "Compress(): Compress data using UEFI standard algorithm\n";
192 
193 STATIC PyMethodDef EfiCompressor_Funcs[] = {
194   {"UefiDecompress", (PyCFunction)UefiDecompress, METH_VARARGS, DecompressDocs},
195   {"UefiCompress", (PyCFunction)UefiCompress, METH_VARARGS, DecompressDocs},
196   {"FrameworkDecompress", (PyCFunction)FrameworkDecompress, METH_VARARGS, DecompressDocs},
197   {"FrameworkCompress", (PyCFunction)FrameworkCompress, METH_VARARGS, DecompressDocs},
198   {NULL, NULL, 0, NULL}
199 };
200 
201 PyMODINIT_FUNC
initEfiCompressor(VOID)202 initEfiCompressor(VOID) {
203   Py_InitModule3("EfiCompressor", EfiCompressor_Funcs, "EFI Compression Algorithm Extension Module");
204 }
205 
206 
207