On Fri Oct 09 10:29:18 2015, amock@marvell.com wrote:
Show quoted text> Hi,
>
> a few ago I stumbled over the error in Win32API::Struct 0.82 when
> unpacking a BYTE / UNSIGNED CHAR buffer.
> After some debugging I found that the buffers are being packed using
> 'a'.$repeat but got unpacked using 'Z'.$repeat.
>
> I'm using plain Strawberry Perl 32 and/or 64 bit on Windows 7 64 bit.
> "This is perl 5, version 22, subversion 0 (v5.22.0) built for MSWin32-
> x86-multi-thread-64int"
>
> I used Win32::API to access FTDI's FTCJTAG.DLL and imported the DLL
> functions using the corresponding .h file and Win32::API::more.
> Great so far! Really easy to import a DLL using the .h file contents.
>
> The buffers were declared :
> Win32::API::Struct->typedef ('WriteDataByteBuffer', qw (
> BYTE data[64]));
> Win32::API::Struct->typedef ('ReadDataByteBuffer', qw (
> BYTE data[64]));
> Win32::API::Struct->typedef ('ReadCmdSequenceDataByteBuffer', qw (
> BYTE data[128]));
>
> Win32::API::Type->typedef('PWriteDataByteBuffer',
> 'WriteDataByteBuffer*');
> Win32::API::Type->typedef('PReadDataByteBuffer',
> 'ReadDataByteBuffer*');
> Win32::API::Type->typedef('PReadCmdSequenceDataByteBuffer',
> 'ReadCmdSequenceDataByteBuffer*');
Do not use Win32::API::Struct like that. First Win32::API::Struct is very inefficient. Second you null term problem is because it was sent through Win32::API and you didn't pass a plain string buffer to be written to. Just pad out a regular scalar with as described in
http://search.cpan.org/~bulkdd/Win32-API/API.pm#CALLING_AN_IMPORTED_FUNCTION
$s = "\x00" x 64;
Then declare the func to Win32::API as a char * or P (I prefer P personally), then pass $s to the $api->Call call.
Also 64 or 128 bytes is not enough per documents of the C API so I dont think you read them correctly.
----------------------------------------------------------------------------------
FTC_STATUS JTAG_Read (FTC_HANDLE ftHandle, BOOL bInstructionTestData, DWORD
dwNumBitsToRead, PReadDataByteBuffer pReadDataBuffer, LPDWORD lpdwNumBytesReturned,
DWORD dwTapControllerState)
This function reads data from an external device ie a device attached to a FT2232D dual device or
FT2232H dual hi-speed device or FT4232H quad hi-speed device. A FT2232D dual device or FT2232H
dual hi-speed device or FT4232H quad hi-speed device communicates with an external device by
simulating the JTAG synchronous protocol.
Parameters
ftHandle
Handle of a FT2232D dual device or FT2232H dual hi-
speed device or FT4232H quad hi-speed device.
bInstructionTestData
Specifies the type of register, that data is to be read from on an
external device. Instruction(TRUE) or test data(FALSE).
dwNumBitsToRead
Specifies the number of bits to be read from an external device.
Valid range 2 to 524280. 524280 bits is equivalent to 64K bytes.
pReadDataBuffer
Pointer to buffer that returns the data read from an external
device. Size of buffer should be set to 65535.
----------------------------------------------------------------------------------
Show quoted text> The JTAG_Read function in FTCJTAG.DLL in my case/for my device returns
> 5 bytes. (4 bytes data DWORD and 1 byte JTAG status bits)
>
> unpack ('Z64', $buffer->data) stops unpacking at the first 0 found ->
> WRONG
>
> unpack ('a64', $buffer->data) unpacks all bytes even zeros and pads
> with 0.
>
> I fixed it just by changing Z to a.
>
> Then while finishing my tasks and documenting, I found the new version
> 0.83_01 that tries to fix something unpacking arrays.
> But unpack ('Z'... for any byte sized array is still wrong, and when
> fixed by a 'a' then the
> Win32::API::_TruncateToWideNull($$itemvalueref) later on kills the
> buffer's values.
>
> IMHO the Z is only correct if the buffer contains a Zero terminted
> string, if the buffer contains any binary data, 'a' is the only valid
> format specifier for the unpack, because 0s (zeros) are preserved.
> Padding a zero-terminated string with 0s does not harm, whereas
> cutting binary data at the first zero is harmful.
How would you extract whether a char array is null termed or not from this struct definition
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365740%28v=vs.85%29.aspx for example?
C lang does not specify whether a char * is random binary or null terminated. There is no way to know this programmatically from any C prototype (COM does know the different between an array of chars and a string
https://msdn.microsoft.com/en-us/library/cc237562.aspx but this module isn't called Win32::COM). Most char *s are printable bytes, not binary data (like a C struct) casted to a char * that is effectively a void *. There are back compat problems that an inline char array in a Win32::API::Struct was already null termed for years.
Show quoted text> I would suggest
> $type = $type_size == 1 ?
> 'Z'.$repeat #have pack truncate to NULL char
> :'a'.($repeat*$type_size); #manually truncate to wide NULL char
> later
>
> to be changed to
> $type = 'a'.($repeat*$type_size);
This causes the treatment of char * (null term) and wchar_t *s (not null term) to be different which was one of the issues in
https://rt.cpan.org/Ticket/Display.html?id=92971 which I fixed.
Show quoted text> Uuuh I can't find Win32::API::_TruncateToWideNull,
It is undocumented, that is why it has _, it is written in XS.