windows-nt/Source/XPSP1/NT/enduser/troubleshoot/launcher/server/tsmapclient.cpp

1266 lines
34 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//
// MODULE: TSMapClient.cpp
//
// PURPOSE: Part of launching a Local Troubleshooter from an arbitrary NT5 application
// Class TSMapClient is available at runtime for mapping from the application's
// way of naming a problem to the Troubleshooter's way.
// Only a single thread should operate on any one object of class TSMapClient. The object is not
// threadsafe.
// In addition to the overtly noted returns, many methods can return a preexisting error.
// However, if the calling program has wishes to ignore an error and continue, we
// recommend an explicit call to inherited method ClearStatus().
// Note that the mapping file is always strictly SBCS (Single Byte Character Set), but the
// calls into this code may use Unicode. This file consequently mixes char and TCHAR.
//
// COMPANY: Saltmine Creative, Inc. (206)-633-4743 support@saltmine.com
//
// AUTHOR: Joe Mabel
//
// ORIGINAL DATE: 2-26-98
//
//
// Version Date By Comments
//--------------------------------------------------------------------
// V0.1 - JM Original
///////////////////////
// TSMapClient
//
// AUTHOR: Joe Mabel
#include "stdafx.h"
#include "TSLError.h"
#include "RSSTACK.H"
#include "TSMapAbstract.h"
#include "TSMap.h"
#include "TSMapClient.h"
// uncomment the following line to turn on Joe's hard-core debugging
//#define KDEBUG 1
#ifdef KDEBUG
static HANDLE hDebugFile = INVALID_HANDLE_VALUE;
static DWORD dwBytesWritten;
#include <stdio.h>
#endif
// because the null string is a perfectly valid value for some strings, we reserve an
// arbitrary implausible value so we don't get a false cache match on startup.
const char * const szBogus = "**BOGUS**";
// Convert TCHAR *szt to char *sz. *sz should point to a big enough buffer
// to contain an SNCS version of *szt. count indicates the size of buffer *sz.
// returns sz (convenient for use in string functions).
static char* ToSBCS (char * const sz, const TCHAR * szt, size_t count)
{
if (sz)
{
if (count != 0 && !szt)
sz[0] = '\0';
else
{
#ifdef _UNICODE
wcstombs( sz, szt, count );
#else
strcpy(sz, szt);
#endif
}
}
return sz;
}
// Convert char *sz to TCHAR *szt. *szt should point to a big enough buffer
// to contain a TCHAR* version of *sz (twice as big if its Unicode).
// count indicates the size of buffer *szt.
// returns szt (convenient for use in string functions).
static TCHAR* FromSBCS (TCHAR * const szt, const char * const sz, size_t count)
{
if (szt)
{
if (count != 0 && !sz)
szt[0] = _T('\0');
else
{
#ifdef _UNICODE
mbstowcs( szt, sz, count);
#else
strcpy(szt, sz);
#endif
}
}
return szt;
}
TSMapClient::TSMapClient(const TCHAR * const sztMapFile)
{
TSMapRuntimeAbstract::TSMapRuntimeAbstract();
_tcscpy(m_sztMapFile, sztMapFile);
m_hMapFile = INVALID_HANDLE_VALUE;
// >>> 1/16/98 we are setting these false until we can arrange to use the same'
// collating sequence in SQL Server & in this code.
m_bAppAlphaOrder = false;
m_bVerAlphaOrder = false;
m_bDevIDAlphaOrder = false;
m_bDevClassGUIDAlphaOrder = false;
m_bProbAlphaOrder = false;
Initialize();
ClearAll();
}
TSMapClient::~TSMapClient()
{
if (m_hMapFile != INVALID_HANDLE_VALUE)
CloseHandle(m_hMapFile);
}
// If not already initialized, open the mapping file & read the header
// Note that this is not thread-safe. Only a single thread should use a given TSMapClient
// object.
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class.
// Typically, on entry m_dwStatus should be 0 and will be left alone if there are no errors
// Can set m_dwStatus to any of the following values:
// TSL_ERROR_MAP_CANT_OPEN_MAP_FILE
// TSL_ERROR_MAP_BAD_HEAD_MAP_FILE
DWORD TSMapClient::Initialize()
{
static bool bInit = false;
DWORD dwStatus = 0;
if (!bInit)
{
m_hMapFile = CreateFile(
m_sztMapFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL, // no security attributes
OPEN_EXISTING,
FILE_FLAG_RANDOM_ACCESS,
NULL // handle to template file
);
if (m_hMapFile == INVALID_HANDLE_VALUE)
{
dwStatus = TSL_ERROR_MAP_CANT_OPEN_MAP_FILE;
}
else
{
DWORD dwBytesRead;
if (!Read( &m_header, sizeof(m_header), &dwBytesRead))
dwStatus = TSL_ERROR_MAP_BAD_HEAD_MAP_FILE;
}
if (dwStatus)
m_dwStatus = dwStatus;
else
bInit = true;
}
return m_dwStatus;
}
// This function sets us back to a starting state, but has no effect on the mapping
// file. It should succeed unless we've encountered a "hard" error, which would indicate
// a bug either in the code or in the mapping file. Note that it wipes out the caching.
// If you want ot leave caching intact, just call inherited method ClearStatus().
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class. returned value is either 0 or a _preexisting_ hard error we can't clear.
DWORD TSMapClient::ClearAll ()
{
if (!HardMappingError(m_dwStatus))
{
ClearStatus();
TSMapRuntimeAbstract::ClearAll();
strcpy(m_szApp, szBogus);
strcpy(m_appmap.szMapped, szBogus);
strcpy(m_szVer, szBogus);
strcpy(m_vermap.szMapped, szBogus);
strcpy(m_szDevID, szBogus);
m_uidDev = uidNil;
strcpy(m_szDevClassGUID, szBogus);
m_uidDevClass = uidNil;
strcpy(m_szProb, szBogus);
m_uidProb = uidNil;
}
return m_dwStatus;
}
// Get information about an application (input sztApp) from the mapping file into m_appmap
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class.
// RETURNS: 0 or TSL_ERROR_UNKNOWN_APP.
// Can also return hard errors:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
// (or preexisting hard error)
DWORD TSMapClient::SetApp (const TCHAR * const sztApp)
{
char szApp[BUFSIZE];
bool bFound = false;
ToSBCS (szApp, sztApp, BUFSIZE);
if (HardMappingError(m_dwStatus))
return m_dwStatus;
else
ClearStatus();
if ( strcmp(szApp, m_szApp) )
{
// it's not already in the cache; let's try to load it.
int cmp = 1; // in alpha order, it's still ahead
DWORD dwPosition;
bool bFirstTime = true;
dwPosition = m_header.dwOffApp;
while (
!m_dwStatus
&& !bFound
&& dwPosition < m_header.dwLastOffApp
&& ! (cmp < 0 && m_bAppAlphaOrder) )
{
if (ReadAppMap (m_appmap, dwPosition, bFirstTime) )
{
cmp = strcmp(szApp, m_appmap.szMapped);
bFound = ( cmp == 0 );
}
bFirstTime = false;
}
if (bFound)
{
strcpy( m_szApp, szApp );
// Different application invalidates the version
strcpy( m_szVer, szBogus );
}
else
m_dwStatus = TSL_ERROR_UNKNOWN_APP;
}
return m_dwStatus;
}
// Get information about a version (input sztVer) from the mapping file into m_vermap.
// A version makes sense only in the context of an application.
// The null string is a valid input value and corresponds to leaving version blank.
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class.
// RETURNS:
// 0 - OK
// TSM_STAT_NEED_APP_TO_SET_VER
// TSL_ERROR_UNKNOWN_VER
// Can also return hard errors:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
// (or preexisting hard error)
DWORD TSMapClient::SetVer (const TCHAR * const sztVer)
{
char szVer[BUFSIZE];
bool bFound = false;
ToSBCS (szVer, sztVer, BUFSIZE);
if (HardMappingError(m_dwStatus))
return m_dwStatus;
else
ClearStatus();
if ( !strcmp(m_szApp, szBogus) )
{
m_dwStatus = TSM_STAT_NEED_APP_TO_SET_VER;
return m_dwStatus;
}
if (strcmp(m_szVer, szVer) )
{
// it's not already in the cache; let's try to load it.
int cmp = 1; // in alpha order, it's still ahead
DWORD dwPosition;
bool bFirstTime = true;
dwPosition = m_appmap.dwOffVer;
while (
!m_dwStatus
&& !bFound
&& dwPosition < m_appmap.dwLastOffVer
&& ! (cmp < 0 && m_bVerAlphaOrder) )
{
if (ReadVerMap (m_vermap, dwPosition, bFirstTime) )
{
cmp = strcmp(szVer, m_vermap.szMapped);
bFound = ( cmp == 0 );
}
bFirstTime = false;
}
if (bFound)
strcpy( m_szVer, szVer );
else
m_dwStatus = TSL_ERROR_UNKNOWN_VER;
}
return m_dwStatus;
}
// INPUT sztProb should be either a problem name or represent a number < 2**16. In the
// former case, we look up the UID in the mapping file. In the latter
// case, we just translate it to a number to get a problem UID.
// The null string is a valid input value and corresponds to leaving version blank. Only
// makes sense if there is a device (or device class) specified before we try to launch.
// Sets m_uidProb, m_szProb
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class.
// RETURNS:
// 0 - OK
// TSL_WARNING_UNKNOWN_APPPROBLEM - This is not necessarily bad, and results in setting
// m_uidProb = uidNil
// Can also return hard errors:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
// (or preexisting hard error)
DWORD TSMapClient::SetProb (const TCHAR * const sztProb)
{
char szProb[BUFSIZE];
bool bIsNumber = true;
ToSBCS (szProb, sztProb, BUFSIZE);
if (HardMappingError(m_dwStatus))
return m_dwStatus;
else
ClearStatus();
// Null string is not a number; any string with a non-digit in it is not a number
if (szProb[0] == '\0')
bIsNumber = false;
else
{
int i = 0;
while (szProb[i] != '\0')
if (! isdigit(szProb[i]))
{
bIsNumber = false;
break;
}
else
i++;
}
if (bIsNumber)
m_uidProb = atoi(szProb);
else if ( strcmp(szProb, m_szProb) )
{
// it's not already in the cache; let's try to load it.
m_uidProb = GetGenericMapToUID(sztProb,
m_header.dwOffProb, m_header.dwLastOffProb, m_bProbAlphaOrder);
if (m_dwStatus == TSM_STAT_UID_NOT_FOUND)
m_dwStatus = TSL_WARNING_UNKNOWN_APPPROBLEM;
if (m_uidProb != uidNil)
strcpy( m_szProb, szProb );
}
return m_dwStatus;
}
// Get information about a device (input sztDevID) from the mapping file into m_appmap.
// The null string is a valid input value and corresponds to no specified device.
// Except for Device Manager, this is typical usage.
// Sets m_uidDev, m_szDev
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class.
// RETURNS:
// 0 - OK
// TSL_WARNING_BAD_DEV_ID - This is not necessarily bad, and results in setting
// m_uidDev = uidNil
// Can also return hard errors:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
// (or preexisting hard error)
DWORD TSMapClient::SetDevID (const TCHAR * const sztDevID)
{
char szDevID[BUFSIZE];
ToSBCS (szDevID, sztDevID, BUFSIZE);
if (HardMappingError(m_dwStatus))
return m_dwStatus;
else
ClearStatus();
if ( strcmp(szDevID, m_szDevID) )
{
// it's not already in the cache; let's try to load it.
m_uidDev = GetGenericMapToUID (sztDevID,
m_header.dwOffDevID, m_header.dwLastOffDevID, m_bDevIDAlphaOrder);
if (m_dwStatus == TSM_STAT_UID_NOT_FOUND)
m_dwStatus = TSL_WARNING_BAD_DEV_ID;
if (m_uidDev != uidNil)
strcpy( m_szDevID, szDevID );
}
return m_dwStatus;
}
// Get information about a device class (input sztDevClassGUID) from the mapping file
// into m_appmap.
// The null string is a valid input value and corresponds to no specified device.
// Except for Device Manager, this is typical usage.
// Sets m_uidDevClass, m_szDevClass
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class.
// RETURNS:
// 0 - OK
// TSL_WARNING_BAD_CLASS_GUID - This is not necessarily bad, and results in setting
// m_uidDevClass = uidNil
// Can also return hard errors:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
// (or preexisting hard error)
DWORD TSMapClient::SetDevClassGUID (const TCHAR * const sztDevClassGUID)
{
char szDevClassGUID[BUFSIZE];
ToSBCS (szDevClassGUID, sztDevClassGUID, BUFSIZE);
if (HardMappingError(m_dwStatus))
return m_dwStatus;
else
ClearStatus();
if ( strcmp(szDevClassGUID, m_szDevClassGUID) )
{
// it's not already in the cache; let's try to load it.
m_uidDevClass = GetGenericMapToUID (sztDevClassGUID,
m_header.dwOffDevClass, m_header.dwLastOffDevClass, m_bDevClassGUIDAlphaOrder);
if (m_dwStatus == TSM_STAT_UID_NOT_FOUND)
m_dwStatus = TSL_WARNING_BAD_CLASS_GUID;
if (m_uidDevClass != uidNil)
strcpy( m_szDevClassGUID, szDevClassGUID );
}
return m_dwStatus;
}
// Set troubleshooter (& possibly problem node) on the basis of application, version,
// problem (ignoring device information). This is achieved by a lookup in the mapping file
// on the basis of previously set member values of this object.
// "TSBN" means "Troubleshooter Belief Network"
// On INPUT, sztTSBN, sztNode must both point to buffers allowing BUFSIZE characters
// OUTPUT: *sztTSBN, *sztNode filled in. If *sztNode is blank, that means launch to
// the problem page of the TSBN with no problem selected.
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class.
// RETURNS:
// 0 - OK
// TSL_ERROR_NO_NETWORK - Mapping failed
// Can also return hard errors:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
// (or preexisting hard error)
DWORD TSMapClient::FromProbToTS (TCHAR * const sztTSBN, TCHAR * const sztNode )
{
char szTSBN[BUFSIZE];
char szNode[BUFSIZE];
FromSBCS (sztTSBN, "", BUFSIZE);
FromSBCS (sztNode, "", BUFSIZE);
if (HardMappingError(m_dwStatus))
return m_dwStatus;
else
ClearStatus();
if ( m_uidProb == uidNil )
{
// Can't do this if m_uidProb is NIL
m_dwStatus = TSL_ERROR_NO_NETWORK;
return m_dwStatus;
}
DWORD dwPosition;
bool bFirstTime = true;
bool bFound = false;
PROBMAP probmap;
dwPosition = m_vermap.dwOffProbUID;
while (
!m_dwStatus
&& !bFound
&& dwPosition < m_vermap.dwLastOffProbUID )
{
if ( ReadProbMap (probmap, dwPosition, bFirstTime) )
{
bFound = ( probmap.uidProb == m_uidProb );
}
if (probmap.uidProb > m_uidProb)
break; // we're past it. No hit.
bFirstTime = false;
}
if (bFound)
{
strcpy( szNode, probmap.szProblemNode );
if (! ReadString (szTSBN, BUFSIZE, probmap.dwOffTSName, TRUE) )
{
m_dwStatus = TSL_ERROR_NO_NETWORK;
}
}
else
m_dwStatus = TSL_ERROR_NO_NETWORK;
FromSBCS (sztTSBN, szTSBN, BUFSIZE);
FromSBCS (sztNode, szNode, BUFSIZE);
return m_dwStatus;
}
// Set troubleshooter (& possibly problem node) on the basis of application, version, device
// and (optionally) problem. This is achieved by a lookup in the mapping file on the basis
// of previously set member values of this object.
// "TSBN" means "Troubleshooter Belief Network"
// On INPUT, sztTSBN, sztNode must both point to buffers allowing BUFSIZE characters
// OUTPUT: *sztTSBN, *sztNode filled in. If *sztNode is blank, that means launch to
// the problem page of the TSBN with no problem selected.
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class.
// RETURNS:
// 0 - OK
// TSL_ERROR_NO_NETWORK - Mapping failed
// Can also return hard errors:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
// (or preexisting hard error)
DWORD TSMapClient::FromDevToTS (TCHAR * const sztTSBN, TCHAR * const sztNode )
{
char szTSBN[BUFSIZE];
char szNode[BUFSIZE];
FromSBCS (sztTSBN, "", BUFSIZE);
FromSBCS (sztNode, "", BUFSIZE);
if (HardMappingError(m_dwStatus))
return m_dwStatus;
else
ClearStatus();
if ( m_uidDev == uidNil )
{
// Can't do this if m_uidDev is NIL
m_dwStatus = TSL_ERROR_NO_NETWORK;
return m_dwStatus;
}
DWORD dwPosition;
bool bFirstTime = true;
bool bFoundDev = false;
bool bFoundProb = false;
DEVMAP devmap;
dwPosition = m_vermap.dwOffDevUID;
// Look in the version-specific list of device-mappings, till we find the right device.
while (
!m_dwStatus
&& !bFoundDev
&& dwPosition < m_vermap.dwLastOffDevUID )
{
if ( ReadDevMap (devmap, dwPosition, bFirstTime) )
{
bFoundDev = ( devmap.uidDev == m_uidDev );
}
if (devmap.uidDev > m_uidDev)
break; // we're past it. No hit.
bFirstTime = false;
}
if ( bFoundDev )
{
// The very first one might be the right problem, or we might have to scan through
// several mappings for this device before we get the right problem.
bFoundProb = ( devmap.uidDev == m_uidDev && devmap.uidProb == m_uidProb );
while (
!m_dwStatus
&& !bFoundProb
&& dwPosition < m_vermap.dwLastOffDevUID )
{
if ( ReadDevMap (devmap, dwPosition ) )
{
bFoundProb = ( devmap.uidDev == m_uidDev && devmap.uidProb == m_uidProb );
}
if ( devmap.uidDev > m_uidDev || devmap.uidProb > m_uidProb )
break; // we're past it. No hit.
}
}
if (bFoundProb)
{
strcpy( szNode, devmap.szProblemNode );
if (! ReadString (szTSBN, BUFSIZE, devmap.dwOffTSName, TRUE) )
{
m_dwStatus = TSL_ERROR_NO_NETWORK;
}
}
else
m_dwStatus = TSL_ERROR_NO_NETWORK;
FromSBCS (sztTSBN, szTSBN, BUFSIZE);
FromSBCS (sztNode, szNode, BUFSIZE);
return m_dwStatus;
}
// Set troubleshooter (& possibly problem node) on the basis of application, version, device
// class and (optionally) problem. This is achieved by a lookup in the mapping file on
// the basis of previously set member values of this object.
// "TSBN" means "Troubleshooter Belief Network"
// On INPUT, sztTSBN, sztNode must both point to buffers allowing BUFSIZE characters
// OUTPUT: *sztTSBN, *sztNode filled in. If *sztNode is blank, that means launch to
// the problem page of the TSBN with no problem selected.
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class.
// RETURNS:
// 0 - OK
// TSL_ERROR_NO_NETWORK - Mapping failed
// Can also return hard errors:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
// (or preexisting hard error)
// >>> There is probably some way to share common code with FromDevToTS()
DWORD TSMapClient::FromDevClassToTS (TCHAR * const sztTSBN, TCHAR * const sztNode )
{
char szTSBN[BUFSIZE];
char szNode[BUFSIZE];
FromSBCS (sztTSBN, "", BUFSIZE);
FromSBCS (sztNode, "", BUFSIZE);
if (HardMappingError(m_dwStatus))
return m_dwStatus;
else
ClearStatus();
#ifdef KDEBUG
char* szStart = "START\n";
char* szEnd = "END\n";
char sz[150];
hDebugFile = CreateFile(
(m_uidProb == uidNil) ? _T("k0debug.txt") : _T("k1debug.txt"),
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
WriteFile(
hDebugFile,
szStart,
strlen(szStart),
&dwBytesWritten,
NULL);
sprintf (sz, "look for DevClassUID %d, ProbUID %d\n", m_uidDevClass, m_uidProb);
WriteFile(
hDebugFile,
sz,
strlen(sz),
&dwBytesWritten,
NULL);
#endif
if ( m_uidDevClass == uidNil )
{
// Can't do this if m_uidDevClass is NIL
m_dwStatus = TSL_ERROR_NO_NETWORK;
return m_dwStatus;
}
DWORD dwPosition;
bool bFirstTime = true;
bool bFoundDevClass = false;
bool bFoundProb = false;
DEVCLASSMAP devclassmap;
dwPosition = m_vermap.dwOffDevClassUID;
// Look in the version-specific list of device-class-mappings, till we find the right device class.
while (
!m_dwStatus
&& !bFoundDevClass
&& dwPosition < m_vermap.dwLastOffDevClassUID )
{
if ( ReadDevClassMap (devclassmap, dwPosition, bFirstTime) )
{
bFoundDevClass = ( devclassmap.uidDevClass == m_uidDevClass );
}
if (devclassmap.uidDevClass > m_uidDevClass)
break; // we're past it. No hit.
bFirstTime = false;
}
if ( bFoundDevClass )
{
#ifdef KDEBUG
sprintf (sz, "found DevClassUID %d w/ ProbUID %d\n", m_uidDevClass, devclassmap.uidProb);
WriteFile(
hDebugFile,
sz,
strlen(sz),
&dwBytesWritten,
NULL);
#endif
// The very first one might be the right problem, or we might have to scan through
// several mappings for this device class before we get the right problem.
bFoundProb = ( devclassmap.uidDevClass == m_uidDevClass && devclassmap.uidProb == m_uidProb );
while (
!m_dwStatus
&& !bFoundProb
&& dwPosition < m_vermap.dwLastOffDevClassUID )
{
if ( ReadDevClassMap (devclassmap, dwPosition) )
{
bFoundProb = ( devclassmap.uidDevClass == m_uidDevClass && devclassmap.uidProb == m_uidProb );
}
if ( devclassmap.uidDevClass > m_uidDevClass || devclassmap.uidProb > m_uidProb )
break; // we're past it. No hit.
#ifdef KDEBUG
sprintf (sz, "found DevClassUID %d w/ ProbUID %d\n", m_uidDevClass, devclassmap.uidProb);
WriteFile(
hDebugFile,
sz,
strlen(sz),
&dwBytesWritten,
NULL);
#endif
}
}
if (bFoundProb)
{
#ifdef KDEBUG
sprintf (sz, "found right problem");
WriteFile(
hDebugFile,
sz,
strlen(sz),
&dwBytesWritten,
NULL);
#endif
strcpy( szNode, devclassmap.szProblemNode );
if (! ReadString (szTSBN, BUFSIZE, devclassmap.dwOffTSName, TRUE) )
{
m_dwStatus = TSL_ERROR_NO_NETWORK;
#ifdef KDEBUG
sprintf (sz, ", but can't read its name\n");
WriteFile(
hDebugFile,
sz,
strlen(sz),
&dwBytesWritten,
NULL);
#endif
}
else
{
#ifdef KDEBUG
sprintf (sz, ": net [%s] node [%s]\n", szTSBN, szNode);
WriteFile(
hDebugFile,
sz,
strlen(sz),
&dwBytesWritten,
NULL);
#endif
}
}
else
{
m_dwStatus = TSL_ERROR_NO_NETWORK;
#ifdef KDEBUG
sprintf (sz, "No match");
WriteFile(
hDebugFile,
sz,
strlen(sz),
&dwBytesWritten,
NULL);
#endif
}
FromSBCS (sztTSBN, szTSBN, BUFSIZE);
FromSBCS (sztNode, szNode, BUFSIZE);
return m_dwStatus;
#ifdef KDEBUG
CloseHandle(hDebugFile);
hDebugFile = INVALID_HANDLE_VALUE;
#endif
}
// To be used after we have failed to find a mapping for the currently selected version.
// Each version can specify a version to try as a default, including the "blank" version,
// which is distinct from "no version".
// The last version in a chain of defaults will "default" to uidNil: "no version".
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
// parent class.
// RETURNS:
// 0 - OK
// TSL_WARNING_END_OF_VER_CHAIN - OK, but there's nothing to default to.
// TSM_STAT_NEED_APP_TO_SET_VER
// TSM_STAT_NEED_VER_TO_SET_VER - there was no version set, so no basis for a default
// TSL_ERROR_UNKNOWN_VER
// Can also return hard errors:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
// (or preexisting hard error)
DWORD TSMapClient::ApplyDefaultVer()
{
bool bFound = false;
if (HardMappingError(m_dwStatus))
return m_dwStatus;
else
ClearStatus();
if ( !strcmp(m_szApp, szBogus) )
{
m_dwStatus = TSM_STAT_NEED_APP_TO_SET_VER;
return m_dwStatus;
}
if ( !strcmp(m_szVer, szBogus) )
{
m_dwStatus = TSM_STAT_NEED_VER_TO_SET_DEF_VER;
return m_dwStatus;
}
DWORD dwPosition;
bool bFirstTime = true;
UID uidDefault = m_vermap.uidDefault;
if (uidDefault == uidNil)
{
m_dwStatus = TSL_WARNING_END_OF_VER_CHAIN;
return m_dwStatus;
}
dwPosition = m_appmap.dwOffVer;
while (
!m_dwStatus
&& !bFound
&& dwPosition < m_appmap.dwLastOffVer )
{
if (ReadVerMap (m_vermap, dwPosition, bFirstTime) )
{
bFound = ( m_vermap.uid == uidDefault );
}
bFirstTime = false;
}
if (bFound)
strcpy( m_szVer, m_vermap.szMapped );
else
m_dwStatus = TSL_ERROR_UNKNOWN_VER;
return m_dwStatus;
}
// Within a particular range of the mapping file, read UIDMAP records to try to map from
// input sztName to a UID.
// Return resulting UID, including possibly UidNil
// Sets m_dwStatus, which can be obtained via GetStatus(), inherited from the parent class.
// Can set m_dwStatus to:
// 0 - OK
// TSM_STAT_UID_NOT_FOUND
// Can also set m_dwStatus to hard errors:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
// (or may be left reflecting a preexisting hard error)
UID TSMapClient::GetGenericMapToUID (const TCHAR * const sztName,
DWORD dwOffFirst, DWORD dwOffLast,
bool bAlphaOrder)
{
char szName[BUFSIZE];
DWORD dwPosition;
UIDMAP uidmap;
bool bFirstTime = true;
bool bFound = false;
ToSBCS (szName, sztName, BUFSIZE);
if (HardMappingError(m_dwStatus))
return m_dwStatus;
else
ClearStatus();
dwPosition = dwOffFirst;
while ( !m_dwStatus && !bFound && dwPosition < dwOffLast)
{
if (ReadUIDMap (uidmap, dwPosition, bFirstTime) )
{
int cmp = strcmp(szName, uidmap.szMapped);
bFound = ( cmp == 0 );
if ( cmp < 0 && bAlphaOrder )
// relying here on alphabetical order; we've passed what we're looking for
break;
}
else
{
m_dwStatus = TSM_STAT_UID_NOT_FOUND;
}
bFirstTime = false;
}
if (bFound)
return uidmap.uid;
else
{
m_dwStatus = TSM_STAT_UID_NOT_FOUND;
return uidNil;
}
}
// ------------------- utility functions ------------------------
// I/O, wrapped the way we are using it.
// SetFilePointerAbsolute sets map file to a location & returns that location if successful
// returns -1 and sets m_dwStatus on failure
// Sets m_dwStatus, which can be obtained via GetStatus(), inherited from the parent class.
// Although, in theory, a bad seek just indicates a bad dwMoveTo value, in practice
// a bad seek would indicate a serious problem either in the mapping file or in the calling
// function: we should only be seeking to offsets which the contents of the mapping file
// told us to seek to.
// RETURNS:
// 0 - OK
// TSL_ERROR_MAP_BAD_SEEK
DWORD TSMapClient::SetFilePointerAbsolute( DWORD dwMoveTo )
{
DWORD dwPosition = SetFilePointer(m_hMapFile, dwMoveTo, NULL, FILE_BEGIN);
if( dwPosition != dwMoveTo)
{
// >>> could call GetLastError, but what do we do with it?
m_dwStatus= TSL_ERROR_MAP_BAD_SEEK;
dwPosition = -1;
}
return dwPosition;
}
// Low-level read n bytes. Calls Win32 function ReadFile.
// Read from map file into lpBuffer
// returns true if requested # of bytes are read
// Returns false and sets m_dwStatus on failure
// Although, in theory, a bad read just indicates (for example) reading past EOF, in practice
// a bad read would indicate a serious problem either in the mapping file or in the calling
// function: we should only be reading (1) the header or (2) records which the contents of
// the mapping file told us to read.
// RETURNS:
// 0 - OK
// TSL_ERROR_MAP_BAD_READ
// TSL_ERROR_MAP_BAD_SEEK
bool TSMapClient::Read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpdwBytesRead)
{
if (! ReadFile( m_hMapFile, lpBuffer, nNumberOfBytesToRead, lpdwBytesRead, NULL)
|| *lpdwBytesRead != nNumberOfBytesToRead )
{
// >>> On ReadFile returning false, could call GetLastError,
// but what do we do with it?
m_dwStatus= TSL_ERROR_MAP_BAD_READ;
return false;
}
return true;
}
// Read a single UIDMAP from the mapping file (maps text to a UID)
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
// OUTPUT uidmap
// RETURNS true on success
// On failure, returns false & sets m_dwStatus:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
bool TSMapClient::ReadUIDMap (UIDMAP &uidmap, DWORD &dwPosition, bool bSetPosition)
{
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
{
DWORD dwBytesRead;
BOOL ret;
// First just read the byte count, then the rest
ret = Read( &uidmap, sizeof(short), &dwBytesRead);
if ( ret )
{
// The first argument below may be a bit confusing. We take a pointer to
// the byte count (a short*) then increment it to point immediately past the
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
ret = Read( (&(uidmap.cb))+1, uidmap.cb - sizeof(short), &dwBytesRead);
if ( ret )
{
dwPosition += uidmap.cb;
return true;
}
}
}
return false;
}
// Read a single APPMAP from the mapping file (contains info about an application)
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
// OUTPUT appmap
// RETURNS true on success
// On failure, returns false & sets m_dwStatus:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
bool TSMapClient::ReadAppMap (APPMAP &appmap, DWORD &dwPosition, bool bSetPosition)
{
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
{
DWORD dwBytesRead;
BOOL ret;
// First just read the byte count, then the rest
ret = Read( &appmap, sizeof(short), &dwBytesRead);
if ( ret )
{
// The first argument below may be a bit confusing. We take a pointer to
// the byte count (a short*) then increment it to point immediately past the
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
ret = Read( (&(appmap.cb))+1, appmap.cb - sizeof(short), &dwBytesRead);
if ( ret )
{
dwPosition += appmap.cb;
return true;
}
}
}
return false;
}
// Read a single VERMAP from the mapping file (contains info about a version)
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
// OUTPUT vermap
// RETURNS true on success
// On failure, returns false & sets m_dwStatus:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
bool TSMapClient::ReadVerMap (VERMAP &vermap, DWORD &dwPosition, bool bSetPosition)
{
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
{
DWORD dwBytesRead;
BOOL ret;
// First just read the byte count, then the rest
ret = Read( &vermap, sizeof(short), &dwBytesRead);
if ( ret )
{
// The first argument below may be a bit confusing. We take a pointer to
// the byte count (a short*) then increment it to point immediately past the
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
ret = Read( (&(vermap.cb))+1, vermap.cb - sizeof(short), &dwBytesRead);
if ( ret )
{
dwPosition += vermap.cb;
return true;
}
}
}
return false;
}
// Read a single PROBMAP from the mapping file (contains a mapping for use by FromProbToTS())
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
// OUTPUT vermap
// RETURNS true on success
// On failure, returns false & sets m_dwStatus:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
bool TSMapClient::ReadProbMap (PROBMAP &probmap, DWORD &dwPosition, bool bSetPosition)
{
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
{
DWORD dwBytesRead;
BOOL ret;
// First just read the byte count, then the rest
ret = Read( &probmap, sizeof(short), &dwBytesRead);
if ( ret )
{
// The first argument below may be a bit confusing. We take a pointer to
// the byte count (a short*) then increment it to point immediately past the
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
ret = Read( (&(probmap.cb))+1, probmap.cb - sizeof(short), &dwBytesRead);
if ( ret )
{
dwPosition += probmap.cb;
return true;
}
}
}
return false;
}
// Read a single DEVMAP from the mapping file (contains a mapping for use by FromDevToTS())
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
// OUTPUT vermap
// RETURNS true on success
// On failure, returns false & sets m_dwStatus:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
bool TSMapClient::ReadDevMap (DEVMAP &devmap, DWORD &dwPosition, bool bSetPosition)
{
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
{
DWORD dwBytesRead;
BOOL ret;
// First just read the byte count, then the rest
ret = Read( &devmap, sizeof(short), &dwBytesRead);
if ( ret )
{
// The first argument below may be a bit confusing. We take a pointer to
// the byte count (a short*) then increment it to point immediately past the
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
ret = Read( (&(devmap.cb))+1, devmap.cb - sizeof(short), &dwBytesRead);
if ( ret )
{
dwPosition += devmap.cb;
return true;
}
}
}
return false;
}
// Read a single DEVCLASSMAP from the mapping file (contains a mapping for use by
// FromDevClassToTS())
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
// OUTPUT vermap
// RETURNS true on success
// On failure, returns false & sets m_dwStatus:
// TSL_ERROR_MAP_BAD_SEEK
// TSL_ERROR_MAP_BAD_READ
bool TSMapClient::ReadDevClassMap (DEVCLASSMAP &devclassmap, DWORD &dwPosition, bool bSetPosition)
{
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
{
DWORD dwBytesRead;
BOOL ret;
// First just read the byte count, then the rest
ret = Read( &devclassmap, sizeof(short), &dwBytesRead);
if ( ret )
{
// The first argument below may be a bit confusing. We take a pointer to
// the byte count (a short*) then increment it to point immediately past the
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
ret = Read( (&(devclassmap.cb))+1, devclassmap.cb - sizeof(short), &dwBytesRead);
if ( ret )
{
dwPosition += devclassmap.cb;
return true;
}
}
}
return false;
}
// Low-level read a null-terminated string. Calls Win32 function ReadFile.
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
// INPUT chMax is maximum # of bytes (not necessarily characters) to read. The last character
// will not actually be read: a null character will always be imposed.
// OUTPUT vermap
// RETURNS true on success
// On failure, returns false & sets m_dwStatus:
// TSL_ERROR_MAP_BAD_SEEK
// Note that on completion the file position is unreliable. It is based on the size of the
// buffer passed in, not the actual string.
bool TSMapClient::ReadString (char * sz, DWORD cbMax, DWORD &dwPosition, bool bSetPosition)
{
DWORD dwBytesRead;
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
{
if (cbMax == 0)
return true;
if ( cbMax == 1 || ReadFile( m_hMapFile, sz, cbMax-1, &dwBytesRead, NULL) )
{
sz[cbMax-1] = '\0';
return true;
}
}
return false;
}
// Once one of these errors has occurred, we consider recovery impossible, except by closing
// this object and opening a new one.
// Although, in theory, a bad seek or read just indicates bad arguments
// to the relevant function, in practice a bad seek or read would indicate
// a serious problem either in the mapping file or in the calling
// function: beyond the header, we should only be seeking to and reading
// from offsets which the contents of the mapping file old us to seek/read.
bool TSMapClient::HardMappingError (DWORD dwStatus)
{
if (TSMapRuntimeAbstract::HardMappingError(dwStatus))
return true;
else
switch (dwStatus)
{
case TSL_ERROR_MAP_BAD_SEEK:
case TSL_ERROR_MAP_BAD_READ:
case TSL_ERROR_MAP_CANT_OPEN_MAP_FILE:
case TSL_ERROR_MAP_BAD_HEAD_MAP_FILE:
return true;
default:
return false;
}
}