/*	Version.cpp
 *
 *		Get the version of this thing, if the version resource is
 *	present
 */

/**********************************************************************

  YAAF is Copyright 1997-1999 by William Woody.

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions 
  are met:

  Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer.

  Neither the name of the copyright holder or other contributors may
  be used to promote products derived from this software without
  specific written prior permission.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  SOFTWARE.
  
  Contact:   woody@alumni.caltech.edu
  Web page:  http://www.pandawave.com/yaaf/

**********************************************************************/

#include <XConfig.h>
#include <XMisc.h>
#include <XDataUtil.h>
#include <XStringUtil.h>

/************************************************************************/
/*																		*/
/*	Version Resource													*/
/*																		*/
/************************************************************************/

#if OPT_MACOS

/*	VersRecord
 *
 *		The 'vers' record
 */

struct VersRecord {
	long			version;
	short			region;
	unsigned char	verstr[2];
};

/*$	XGGetAppVersion
 *
 *		Get the application version from this application. On the
 *	Macintosh, look for the 'vers'1 resource. On Windows, extract
 *	this from the version resource. On Unix, punt.
 *
 *		The total length of the string is supplied in the #maxlen#
 *	parameter, so you can assure yourself your string won't overflow.
 */

boolean XGGetAppVersion(char *str, uint16 maxlen)
{
	VersRecord **v;
	
	/*
	 *	Get version string
	 */
	
	v = (VersRecord **)Get1Resource('vers',1);
	if (v == NULL) return false;
	HLock((Handle)v);
	ncvtp2c(str,(**v).verstr,maxlen);
	HUnlock((Handle)v);
	ReleaseResource((Handle)v);
	return true;
}

#endif

#if OPT_WINOS

/*	CompareString
 *
 *		Compare unicode string
 */

static bool CompareString(unsigned short *ucode, char *str)
{
	while (*str && (*str == (char)*ucode)) str++, ucode++;
	if ((*str == 0) && (*ucode == 0)) return true;
	return false;
}

/*	CompareVar
 *
 *		Compare var resource
 */

static bool CompareVar(void *var, char *str)
{
	return CompareString(3+(unsigned short *)var,str);
}

/*	SearchVar
 *
 *		Search within the value until I find the string or run
 *	out of vars
 */

static void *SearchVar(void *var, short start, char *str)
{
	void *ptr;
	short len = *((short *)var);
	
	while (start < len) {
		/*
		 *	Compare the variable object pointed to here
		 */
		
		ptr = (void *)(start + (char *)var);
		if (CompareVar(ptr,str)) return ptr;
		start += *((short *)ptr);
		if (0 != (start % 4)) start += 4 - start % 4;
	}
	return NULL;
}

/*	FindChildOffset
 *
 *		Find the offset of the child
 */

static short FindChildOffset(void *var)
{
	short off;
	short *ptr = (short *)var;
	
	off = 6;
	while (ptr[off] != 0) off++;
	off++;						// skip terminating null
	if ((off % 2) == 1) off++;
	return off*2;
}

/*	ExtractValue
 *
 *		Extract the value parameter of a string value list
 */

static void ExtractValue(void *var, char *value, uint16 maxlen)
{
	short off = FindChildOffset(var)/2;
	short *ptr = (short *)var;
	while ((ptr[off] != 0) && (--maxlen > 0)) *value++ = (char)ptr[off++];
	*value = 0;
}

/*	XGGetAppVersion
 *
 *		Get the Windows version information from me
 */

boolean XGGetAppVersion(char *str, uint16 maxlen)
{
	HRSRC ressrc;
	HGLOBAL resdata;
	LPVOID data;
	void *var;
	bool retval;
	
	/*
	 *	Get my own version resource
	 */
	
	ressrc = FindResource(NULL,MAKEINTRESOURCE(VS_VERSION_INFO),RT_VERSION);
	if (ressrc == NULL) return false;
	resdata = LoadResource(NULL,ressrc);
	if (resdata == NULL) return false;
	data = LockResource(resdata);
	
	/*
	 *	Extract resource data. Do this myself because I can't rely
	 *	on the version library--for some reason, the resource is
	 *	stored in a different format than expected by VerQueryValue
	 */
	
	var = (void *)data;														// root
	var = (void *)(FindChildOffset(var) + 13*sizeof(long) + (char *)var);	// VS_VERSION_INFO
	if (var) var = (void *)(FindChildOffset(var) + (char *)var);			// StringFileInfo
	if (var) var = SearchVar(var,FindChildOffset(var),"FileVersion");		// FileVersion
	if (var) {
		retval = true;
		ExtractValue(var,str,maxlen);
	} else {
		retval = false;
	}
		
	UnlockResource(resdata);
	FreeResource(resdata);
	return retval;
}

#endif

#if OPT_XWIN

/*	XGGetAppVersion
 *
 *		There is no version information for Unix, so punt.
 */

bool XGGetAppVersion(char *str)
{
	return false;
}

#endif
