#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <winver.h>
MODULE = Win32::File::Ver PACKAGE = Win32::File::Ver
SV *
GetFileVersion ( file )
char * file
PROTOTYPE: $
PREINIT:
unsigned long *dw,langs,foo;
unsigned int size;
void *chunk, *base;
char temp[256], temp2[16];
HV *h, *r, *l, *th;
SV *ts;
CODE:
h = (HV *) sv_2mortal( (SV *) newHV() );
r = newHV();
ts = newRV_noinc ( (SV *) r );
if ( ! hv_store ( h, "Raw", 3, ts, 0 ) ) SvREFCNT_dec ( ts );
size = GetFileVersionInfoSize ( file, &foo );
if ( ! size ) XSRETURN_UNDEF;
chunk = malloc ( size );
if ( ! chunk ) XSRETURN_UNDEF;
if ( ! GetFileVersionInfo ( file, foo, size, chunk ) ) XSRETURN_UNDEF;
if ( ! VerQueryValue ( chunk, "\\", &base, &size ) ) XSRETURN_UNDEF;
dw = (unsigned long *)base;
/* File Version */
sprintf ( temp, "%u.%u.%u.%u", (dw[2]>>16), (dw[2]&0xffff), (dw[3]>> 16), (dw[3]&0xffff) );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( h, "FileVersion", 11, ts, 0 ) ) SvREFCNT_dec ( ts );
sprintf ( temp, "%08X%08X", dw[2], dw[3] );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( r, "FileVersion", 11, ts, 0 ) ) SvREFCNT_dec ( ts );
/* Product Version */
sprintf ( temp, "%u.%u.%u.%u", (dw[4]>>16), (dw[4]&0xffff), (dw[5]>> 16), (dw[5]&0xffff) );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( h, "ProductVersion", 14, ts, 0 ) ) SvREFCNT_dec ( ts );
sprintf ( temp, "%08X%08X", dw[4], dw[5] );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( r, "ProductVersion", 14, ts, 0 ) ) SvREFCNT_dec ( ts );
/* Flags */
foo = dw[6] & dw[7];
th = newHV();
/* Brace thyselves */
if ( ( foo & VS_FF_DEBUG ) && ( !hv_store(th, "Debug", 5, ts = newSVuv(1), 0) ) ) SvREFCNT_dec (ts);
if ( ( foo & VS_FF_PRERELEASE ) && ( !hv_store(th, "Prerelease", 10, ts = newSVuv(1), 0) ) ) SvREFCNT_dec(ts);
if ( ( foo & VS_FF_PATCHED ) && ( !hv_store(th, "Patched", 7, ts = newSVuv(1), 0) ) ) SvREFCNT_dec(ts);
if ( ( foo & VS_FF_PRIVATEBUILD ) && ( !hv_store(th, "PrivateBuild", 12, ts = newSVuv(1), 0) ) ) SvREFCNT_dec(ts);
if ( ( foo & VS_FF_INFOINFERRED ) && ( !hv_store(th, "InfoInferred", 12, ts = newSVuv(1), 0) ) ) SvREFCNT_dec(ts);
if ( ( foo & VS_FF_SPECIALBUILD ) && ( !hv_store(th, "SpecialBuild", 12, ts = newSVuv(1), 0) ) ) SvREFCNT_dec(ts);
ts = newRV_noinc ( (SV *) th );
if ( ! hv_store ( h, "Flags", 5, ts, 0 ) ) SvREFCNT_dec ( ts );
sprintf ( temp, "%08X", dw[6] );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( r, "FlagMask", 8, ts, 0 ) ) SvREFCNT_dec ( ts );
sprintf ( temp, "%08X", dw[7] );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( r, "Flags", 5, ts, 0 ) ) SvREFCNT_dec ( ts );
/* OS */
switch ( dw[8] & 0xffff0000 ) {
case VOS_DOS: strcpy ( temp2, "DOS" ); break;
case VOS_OS216: strcpy ( temp2, "OS/2 16" ); break;
case VOS_OS232: strcpy ( temp2, "OS/2 32" ); break;
case VOS_NT: strcpy ( temp2, "NT" ); break;
#ifdef VOS_WINCE /* not in all versions of winver.h */
case VOS_WINCE: strcpy ( temp2, "WINCE" ); break;
#endif
default:
case VOS_UNKNOWN: strcpy ( temp2, "Unknown" ); break;
}
switch ( dw[8] & 0xffff ) {
case VOS__WINDOWS16: sprintf ( temp, "%s/Win16", temp2 ); break;
case VOS__PM16: sprintf ( temp, "%s/PM16", temp2 ); break;
case VOS__PM32: sprintf ( temp, "%s/PM32", temp2 ); break;
case VOS__WINDOWS32: sprintf ( temp, "%s/Win32", temp2 ); break;
default:
case VOS__BASE: sprintf ( temp, "%s/Unknown", temp2 ); break;
}
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( h, "OS", 2, ts, 0 ) ) SvREFCNT_dec ( ts );
sprintf ( temp, "%08X", dw[8] );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( r, "OS", 2, ts, 0 ) ) SvREFCNT_dec ( ts );
/* Type */
switch ( dw[9] ) {
case VFT_APP: strcpy ( temp, "Application" ); break;
case VFT_DLL: strcpy ( temp, "DLL" ); break;
case VFT_DRV: switch ( dw[10] ) {
case VFT2_DRV_PRINTER: strcpy ( temp, "Printer Driver" ); break;
case VFT2_DRV_KEYBOARD: strcpy ( temp, "Keyboard Driver" ); break;
case VFT2_DRV_LANGUAGE: strcpy ( temp, "Language Driver" ); break;
case VFT2_DRV_DISPLAY: strcpy ( temp, "Display Driver" ); break;
case VFT2_DRV_MOUSE: strcpy ( temp, "Mouse Driver" ); break;
case VFT2_DRV_NETWORK: strcpy ( temp, "Network Driver" ); break;
case VFT2_DRV_SYSTEM: strcpy ( temp, "System Driver" ); break;
case VFT2_DRV_INSTALLABLE: strcpy ( temp, "Installable Driver" ); break;
case VFT2_DRV_SOUND: strcpy ( temp, "Sound Driver" ); break;
case VFT2_DRV_COMM: strcpy ( temp, "Communications Driver" ); break;
case VFT2_DRV_INPUTMETHOD: strcpy ( temp, "Input Method Driver" ); break;
#ifdef VFT2_DRV_VERSIONED_PRINTER /* not in all versions of winver.h */
case VFT2_DRV_VERSIONED_PRINTER: strcpy ( temp, "Versioned Printer Driver" ); break;
#endif
default:
case VFT2_UNKNOWN: strcpy ( temp, "Unknown Driver" ); break;
} break;
case VFT_FONT: switch ( dw[10] ) {
case VFT2_FONT_RASTER: strcpy ( temp, "Raster Font" ); break;
case VFT2_FONT_VECTOR: strcpy ( temp, "Vector Font" ); break;
case VFT2_FONT_TRUETYPE: strcpy ( temp, "TrueType Font" ); break;
default:
case VFT2_UNKNOWN: strcpy ( temp, "Unknown Font" ); break;
} break;
case VFT_VXD: strcpy ( temp, "Virtual Device Driver" ); break;
case VFT_STATIC_LIB: strcpy ( temp, "Static Library" ); break;
default:
case VFT_UNKNOWN: strcpy ( temp, "Unknown" ); break;
}
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( h, "Type", 4, ts, 0 ) ) SvREFCNT_dec ( ts );
sprintf ( temp, "%08X", dw[9] );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( r, "Type", 4, ts, 0 ) ) SvREFCNT_dec ( ts );
sprintf ( temp, "%08X", dw[10] );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( r, "SubType", 7, ts, 0 ) ) SvREFCNT_dec ( ts );
/* Date */
sprintf ( temp, "%08X%08X", dw[11], dw[12] );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( h, "Date", 4, ts, 0 ) ) SvREFCNT_dec ( ts );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( r, "Date", 4, ts, 0 ) ) SvREFCNT_dec ( ts );
/* Variable Part */
if ( ! VerQueryValue ( chunk, "\\VarFileInfo\\Translation", &base, &size ) ) XSRETURN_UNDEF; /* XXX */
dw = (unsigned long *)base;
langs = size / sizeof ( DWORD );
if ( langs ) {
l = newHV();
ts = newRV_noinc ( (SV *) l );
if ( ! hv_store ( h, "Lang", 4, ts, 0 ) ) SvREFCNT_dec ( ts );
}
/* iterate over langage codings */
for ( foo = 0; foo < langs; foo++ ) {
th = newHV();
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\Comments", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "Comments", 8, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\CompanyName", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "CompanyName", 11, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\FileDescription", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "FileDescription", 15, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\FileVersion", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "FileVersion", 11, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\InternalName", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "InternalName", 12, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\LegalCopyright", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "Copyright", 9, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\LegalTrademarks", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "Trademarks", 10, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\OriginalFilename", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "OriginalFilename", 16, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\ProductName", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "ProductName", 11, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\ProductVersion", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "ProductVersion", 14, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\PrivateBuild", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "PrivateBuild", 12, ts, 0 ) ) SvREFCNT_dec ( ts );
}
sprintf ( temp, "\\StringFileInfo\\%04x%04x\\SpecialBuild", dw[foo] & 0xffff, dw[foo] >> 16 );
if ( VerQueryValue ( chunk, temp, &base, &size ) && size ) {
sprintf ( temp, "%.*s", size, base );
ts = newSVpv ( temp, 0 );
if ( ! hv_store ( th, "SpecialBuild", 12, ts, 0 ) ) SvREFCNT_dec ( ts );
}
VerLanguageName ( dw[foo], temp, 255 );
ts = newRV_noinc ( (SV *) th );
if ( ! hv_store ( l, temp, strlen ( temp ), ts, 0 ) ) SvREFCNT_dec ( ts );
}
free ( chunk );
RETVAL = newRV_inc ( (SV *) h );
OUTPUT:
RETVAL