我正在尝试从Python中访问两个用C语言编写的传统解压缩函数,这些函数目前可以通过DLL获得(我有C源代码)。
函数传递(部分)填充的C结构,并使用此信息压缩或解压缩提供的缓冲区中的数据。
这是函数的调用方式。我为Python兼容性添加了__cdecl。
// Both functions return 0 on success and nonzero value on failure
int __cdecl pkimplode(struct pkstream *pStr);
int __cdecl pkexplode(struct pkstream *pStr);
这是C:中定义的pkstream结构
struct pkstream {
unsigned char *pInBuffer; // Pointer to input buffer
unsigned int nInSize; // Size of input buffer
unsigned char *pOutBuffer; // Pointer to output buffer
unsigned int nOutSize; // Size of output buffer upon return
unsigned char nLitSize; // Specifies fixed or var size literal bytes
unsigned char nDictSizeByte; // Dictionary size; either 1024, 2048, or 4096
// The rest of the members of this struct are used internally,
// so setting these values outside pkimplode or pkexplode has no effect
unsigned char *pInPos; // Current position in input buffer
unsigned char *pOutPos; // Current position in output buffer
unsigned char nBits; // Number of bits in bit buffer
unsigned long nBitBuffer; // Stores bits until enough to output a byte
unsigned char *pDictPos; // Position in dictionary
unsigned int nDictSize; // Maximum size of dictionary
unsigned int nCurDictSize; // Current size of dictionary
unsigned char Dict[0x1000]; // Sliding dictionary used for compdecomp
};
这是我在Python中镜像这个结构的尝试。
# Define the pkstream struct
class PKSTREAM(Structure):
_fields_ = [('pInBuffer', c_ubyte),
('nInSize', c_uint),
('pOutBuffer', c_ubyte),
('nOutSize', c_uint),
('nLitSize', c_ubyte),
('nDictSizeByte', c_ubyte),
('pInPos', c_ubyte),
('pOutPos', c_ubyte),
('nBits', c_ubyte),
('nBitBuffer', c_ulong),
('pDictPos', c_ubyte),
('nDictSize', c_uint),
('nCurDictSize', c_uint),
('Dict', c_ubyte)]
我真的很感谢以下问题提供了一些帮助(我选择在前端提问,而不仅仅是“wing”它,希望显而易见的原因):
我不确定是否将c_ubyte,c_char或c_char_p用于 unsigned char 类型的成员。 c_ubyte最接近地映射到unsigned char的ctypes(至少根据文档),但实际上是?int / long?在Python中。
有时成员是一个指针到一个unsigned char ...这会映射到c_char_p吗? ctypes docs说ALL byte& unicode字符串无论如何都作为指针传递,那么我需要为此做些什么规定呢?
我需要为函数提供pOutBuffer,该函数应该是指向函数可以复制de /压缩数据的已分配内存位置的指针。我相信我应该使用create_string_buffer()为它创建一个适当大小的缓冲区?
我还需要知道如何定义成员 Dict [0x1000] ,它看起来(对我来说)创建一个4096字节的缓冲区供内部使用。我知道我的定义显然是错误的,但不知道应该如何定义?
C函数是否应该被装饰为__stdcall或__cdecl? (我已经在一些测试DLL上使用了后者,因为到目前为止我一直在努力)。
任何反馈都会非常感激!
提前致谢,
詹姆斯
答案 0 :(得分:2)
如果结构中的数据是指针,则必须将其声明为Python端的指针。
这样做的一种方法是在ctypes中使用POINTER
实用程序 - 它是一个比ctypes.c_char_p
更高级别的对象(并且与此不完全兼容) - 但是您的代码将变为更具可读性。此外,为了模拟C数组,基本ctypes类型可以乘以标量,返回的对象是可以用作相同大小的基本类型的C向量的对象 - (因此Dict字段可以定义为吼叫,c_ubyte * 4096
)
请注意,虽然char
相当于c_ubyte
,但int
相当于c_int
而非c_uint
,同样适用于long
。< / p>
您的结构定义未声明指向的缓冲区为const
。如果你传递一个python字符串(不可变),你的库试图改变它,你将得到错误。相反,你应该传递从create_string_buffer
返回的可变内存,由你的字符串初始化。
POINTER = ctypes.POINTER
# Define the pkstream struct
class PKSTREAM(Structure):
_fields_ = [('pInBuffer', POINTER(c_char)),
('nInSize', c_int),
('pOutBuffer', POINTER(c_char)),
('nOutSize', c_int),
('nLitSize', c_char),
('nDictSizeByte', c_char),
('pInPos', POINTER(c_char)),
('pOutPos', POINTER(c_char)),
('nBits', c_char),
('nBitBuffer', c_long),
('pDictPos', POINTER(c_char)),
('nDictSize', c_int),
('nCurDictSize', c_int),
('Dict', c_char * 0x1000)]
至于(5),我不知道你应该如何装饰你的C函数 - 使用任何有用的东西。