Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5389 lines
153 KiB

// FILE: WispApis.c
//
#include <stdlib.h>
#include "volcanop.h"
#include "RecTypes.h"
#include "RecApis.h"
#include <Limits.h>
#include <strsafe.h>
#include "TpcError.h"
#include "TpgHandle.h"
#include "res.h"
//#define ENABLE_CONFIDENCE_LEVEL
#define LARGE_BREAKS 500
// definitions of possible handle types that WISP used
#define TPG_HRECOCONTEXT (1)
#define TPG_HRECOGNIZER (2)
#define TPG_HRECOALT (3)
//Why cannot we include penwin.h???? I have to redefine everything I need....
#define SYV_UNKNOWN 0x00000001L
BOOL SymbolToCharacterW(SYV *pSyv, int cSyv, WCHAR *wsz, int *pConv);
// If this pointer is non-NULL, then free input is enabled.
extern BBOX_PROB_TABLE *g_pProbTable;
// String identifying which language is loaded
extern wchar_t *g_szRecognizerLanguage;
extern HINSTANCE g_hInstanceDllCode;
#define NUMBER_OF_ALTERNATES 10
#define TAB_STROKE_INC 30
// {7DFE11A7-FB5D-4958-8765-154ADF0D833F}
static const GUID GUID_CONFIDENCELEVEL =
{ 0x7dfe11a7, 0xfb5d, 0x4958, { 0x87, 0x65, 0x15, 0x4a, 0xdf, 0x0d, 0x83, 0x3f } };
// {8CC24B27-30A9-4b96-9056-2D3A90DA0727}
static const GUID GUID_LINEMETRICS =
{ 0x8cc24b27, 0x30a9, 0x4b96, { 0x90, 0x56, 0x2d, 0x3a, 0x90, 0xda, 0x07, 0x27 } };
// {6D4087D7-61D2-495f-9293-5B7B1C3FCEAB}
static const CLSID JPN_CLSID =
{ 0x6D4087D7, 0x61D2, 0x495f, { 0x92, 0x93, 0x5B, 0x7B, 0x1C, 0x3F, 0xCE, 0xAB } };
static const CLSID KOR_CLSID =
{ 0x6D5087D7, 0x61D2, 0x495f, { 0x92, 0x93, 0x5B, 0x7B, 0x1C, 0x3F, 0xCE, 0xAB } };
static const CLSID CHS_CLSID =
{ 0x6D6087D7, 0x61D2, 0x495f, { 0x92, 0x93, 0x5B, 0x7B, 0x1C, 0x3F, 0xCE, 0xAB } };
static const CLSID CHT_CLSID =
{ 0x6D7087D7, 0x61D2, 0x495f, { 0x92, 0x93, 0x5B, 0x7B, 0x1C, 0x3F, 0xCE, 0xAB } };
//
// Definitions of strucure which pointers are used
// to define the WISP handles (HRECOGNIZER, HRECOCONTEXT
// HRECOALTERNATE)
////////////////////////////////////////////////////////
// This is the structure used for the WISP recognizer
// There is no data, because we have nothing to store
struct WispRec
{
long unused;
};
// This is the structure for WISP alternates
// It contains an array of column used in the
// lattice and an array of indexes used in
// those columns.
// We alse cache the reco context for which
// this alternate is valis, the length of the
// string this alternate corresponds to and
// the original RECO_RANGE this alternate was
// produced from (in a call to GetAlternateList
// or other)
struct WispAlternate
{
HRECOCONTEXT hrc;
int *pIndexInColumn;
int *pColumnIndex;
int iNumberOfColumns;
int iLength;
RECO_RANGE OriginalRecoRange;
};
// This is the WISP structure for the reco context.
// It contains information on the guide used, the
// CAC modem the number of strokes currently
// entered, the context (prefix)
// It also contains the handle to the HWX reco
// context
// We store the lattice so that we not need to
// recreate it every time we are asked for it
struct WispContext
{
HRC hrc;
RECO_GUIDE *pGuide;
ULONG uiGuideIndex;
BOOL bIsBoxed;
BOOL bIsCAC;
BOOL bCACEndInk;
ULONG iCACMode;
UINT uAbort;
ULONG ulCurrentStrokeCount;
BOOL bHasTextContext; // Whether any context has been set
WCHAR *wszBefore; // Context before ink
WCHAR *wszAfter; // Context after ink
DWORD dwFlags; // Flags
WCHAR *wszFactoid; // Factoid
// Lattice for the automation code, with associated data structures
RECO_LATTICE *pLattice;
RECO_LATTICE_PROPERTY *pLatticeProperties;
BYTE *pLatticePropertyValues;
RECO_LATTICE_PROPERTY **ppLatticeProperties;
};
// Structure for the alternate list recursive call
////////////////////////////////////////////////
typedef struct tagAltRank
{
struct WispAlternate *wispalt;
FLOAT fScore;
struct tagAltRank *next;
BOOL bCurrentPath;
} AltRank;
typedef struct tagAltRankList
{
AltRank *pFirst;
AltRank *pLast;
ULONG ulSize;
} AltRankList;
typedef struct tagDiffBreakElement
{
int iColumn;
int iIndex;
struct tagDiffBreakElement *pNext;
} DiffBreakElement;
typedef struct tagDifBreakList
{
int iColumnCount;
DiffBreakElement *pFirst;
float score;
BOOL bCurrentPath;
} DifBreakList;
typedef struct tagDifBreakAltStruct
{
VRC *vrc; // the recognizer data structure
int iFirstStroke; // the first stroke in the original alternate
ULONG ulMax; // Max alternates that we want to return
int iLastChar; // This is to put in the original reco range of the alternate
int iFirstChar; // This is to put in the original reco range of the alternate
AltRankList *paltRankList; // List of Alternates
int iMode; // Segmentation mode (DIFF_BREAK, ...)
} DifBreakAltStruct;
/////////////////////////////////////////////////////
// Declare the GUIDs and consts of the Packet description
/////////////////////////////////////////////////////
const GUID g_guidx ={ 0x598a6a8f, 0x52c0, 0x4ba0, { 0x93, 0xaf, 0xaf, 0x35, 0x74, 0x11, 0xa5, 0x61 } };
const GUID g_guidy = { 0xb53f9f75, 0x04e0, 0x4498, { 0xa7, 0xee, 0xc3, 0x0d, 0xbb, 0x5a, 0x90, 0x11 } };
const PROPERTY_METRICS g_DefaultPropMetrics = { LONG_MIN, LONG_MAX, PROPERTY_UNITS_DEFAULT, 1.0 };
/////////////////////////////////////////////////////
// Helper function to bubble sort an array
/////////////////////////////////////////////////////
// I use a bubble sort because most likely if the
// array is not already sorted, we probably have one or
// two inversion. This is caused by the fact that
// people usually write the letters in a word in
// the correct order
BOOL SlowSort(ULONG *pTab, ULONG ulSize)
{
ULONG i, j, temp;
BOOL bPermut;
// Stupid bubble sort
for (i = 0; i<ulSize; i++)
{
bPermut = FALSE;
for (j = 0; j < ulSize-1-i; j++)
{
if (pTab[j] > pTab[j+1])
{
bPermut = TRUE;
temp = pTab[j];
pTab[j] = pTab[j+1];
pTab[j+1] = temp;
}
}
if (!bPermut) return TRUE;
}
return TRUE;
}
/////////////////////////////////////////////////////
// Implementation of the Wisp Reco Apis
/////////////////////////////////////////////////////
// CreateRecognizer
// Returns a recognizer handle to the recognizer
// corresponding to the passed CLSID. In the case
// of this dll, we only support one CLSID so we will
// not even check for the value of the clsid
// (even if the clsid is null)
//
// Parameter:
// pCLSID [in] : The pointer to the CLSID
// that determines what recognizer we want
// phrec [out] : The address of the returned recognizer
// handle.
//////////////////////////////////////////////////////////////////////
HRESULT WINAPI CreateRecognizer(CLSID *pCLSID, HRECOGNIZER *phrec)
{
struct WispRec *pRec;
// We might want to make NULL illegal later.
if (pCLSID != NULL && IsBadReadPtr(pCLSID, sizeof(CLSID)))
{
return E_POINTER;
}
// validate the pointer
if (IsBadWritePtr(phrec, sizeof(HRECOGNIZER)))
{
return E_POINTER;
}
// initialize the east asian recognizers
#ifdef USE_RESOURCES
if (!HwxConfig())
{
return E_FAIL;
}
#endif
// We might want to make NULL illegal later.
if (pCLSID != NULL)
{
if (wcscmp(g_szRecognizerLanguage, L"JPN") == 0 &&
!IsEqualCLSID(pCLSID, &JPN_CLSID))
{
return E_INVALIDARG;
}
if (wcscmp(g_szRecognizerLanguage, L"CHS") == 0 &&
!IsEqualCLSID(pCLSID, &CHS_CLSID))
{
return E_INVALIDARG;
}
if (wcscmp(g_szRecognizerLanguage, L"CHT") == 0 &&
!IsEqualCLSID(pCLSID, &CHT_CLSID))
{
return E_INVALIDARG;
}
if (wcscmp(g_szRecognizerLanguage, L"KOR") == 0 &&
!IsEqualCLSID(pCLSID, &KOR_CLSID))
{
return E_INVALIDARG;
}
}
// We only have one CLSID per recognizer so always return an hrec...
pRec = (struct WispRec*)ExternAlloc(sizeof(*pRec));
if (NULL == pRec)
{
return E_OUTOFMEMORY;
}
(*phrec) = (HRECOGNIZER)CreateTpgHandle(TPG_HRECOGNIZER, pRec);
if (0 == (*phrec))
{
ExternFree(pRec);
return E_OUTOFMEMORY;
}
return S_OK;
}
// DestroyRecognizer
// Destroys a recognizer handle. Free the associate memory
//
// Parameter:
// hrec [in] : handle to the recognizer
/////////////////////////////////////////////////////////////
HRESULT WINAPI DestroyRecognizer(HRECOGNIZER hrec)
{
struct WispRec *pRec;
// destroy the handle and return the corresponding pointer
pRec = (struct WispRec*)DestroyTpgHandle((HANDLE)hrec, TPG_HRECOGNIZER);
if (NULL == pRec)
{
return E_INVALIDARG;
}
#ifdef USE_RESOURCES
if (!HwxUnconfig(TRUE))
{
return E_FAIL;
}
#endif
ExternFree(pRec);
return S_OK;
}
// GetRecoAttributes
// This function returns the reco attributes corresponding
// to a given recognizer. Since we only have one recognizer
// type we always return the same things.
//
// Parameters:
// hrc [in] : The handle to the recognizer we want the
// the attributes for.
// pRecoAttrs [out] : Address of the user allocated buffer
// to hold the reco attributes.
///////////////////////////////////////////////////////////////////////////
HRESULT WINAPI GetRecoAttributes(HRECOGNIZER hrec, RECO_ATTRS* pRecoAttrs)
{
HRESULT hr = S_OK;
HRSRC hrsrc = NULL;
HGLOBAL hg = NULL;
LPBYTE pv = NULL;
WORD wCurrentCount = 0;
WORD wRecognizerCount = 0;
DWORD dwRecoCapa;
WORD wLanguageCount;
WORD *aLanguages;
WORD iLang;
struct WispRec *pRec;
if (IsBadWritePtr(pRecoAttrs, sizeof(RECO_ATTRS)))
return E_POINTER;
// Check the recognizer handle
pRec = (struct WispRec*)FindTpgHandle((HANDLE)hrec, TPG_HRECOGNIZER);
if (NULL == pRec)
{
return E_INVALIDARG;
}
ZeroMemory(pRecoAttrs, sizeof(RECO_ATTRS));
// Update the global structure is necessary
// Load the resources
// Load the recognizer friendly name
if (0 == LoadStringW(g_hInstanceDllCode, // handle to resource module
RESID_WISP_FRIENDLYNAME, // resource identifier
pRecoAttrs->awcFriendlyName, // resource buffer
sizeof(pRecoAttrs->awcFriendlyName) / sizeof(WCHAR) // size of buffer
))
{
hr = E_FAIL;
}
// Load the recognizer vendor name
if (0 == LoadStringW(g_hInstanceDllCode, // handle to resource module
RESID_WISP_VENDORNAME, // resource identifier
pRecoAttrs->awcVendorName, // resource buffer
sizeof(pRecoAttrs->awcVendorName) / sizeof(WCHAR) // size of buffer
))
{
hr = E_FAIL;
}
if (SUCCEEDED(hr))
{
hrsrc = FindResource(g_hInstanceDllCode, // module handle
(LPCTSTR)RESID_WISP_DATA, // resource name
(LPCTSTR)RT_RCDATA // resource type
);
if (NULL == hrsrc)
{
// The resource is not found!
ASSERT(NULL != hrsrc);
hr = E_FAIL;
}
}
if (SUCCEEDED(hr))
{
hg = LoadResource(
g_hInstanceDllCode, // module handle
hrsrc // resource handle
);
if (NULL == hg)
{
hr = E_FAIL;
}
}
if (SUCCEEDED(hr))
{
pv = (LPBYTE)LockResource(
hg // handle to resource
);
if (NULL == pv)
{
hr = E_FAIL;
}
}
dwRecoCapa = *((DWORD*)pv);
pv += sizeof(dwRecoCapa);
wLanguageCount = *((WORD*)pv);
pv += sizeof(wLanguageCount);
aLanguages = (WORD*)pv;
pv += wLanguageCount * sizeof(WORD);
// Fill the reco attricute structure for this recognizer
// Add the languages
ASSERT(wLanguageCount < 64);
for (iLang = 0; iLang < wLanguageCount; iLang++)
{
pRecoAttrs->awLanguageId[iLang] = aLanguages[iLang];
}
// End the list with a NULL
pRecoAttrs->awLanguageId[wLanguageCount] = 0;
// Add the recocapability flag
pRecoAttrs->dwRecoCapabilityFlags = dwRecoCapa;
return hr;
}
// CreateRecoContext
// This function creates a reco context for a given recognizer
// Since we only have one type of recognizers in this dll,
// always return the same kind of reco context.
//
// Parameters:
// hrec [in] : Handle to the recognizer we want to create a
// reco context for.
// phrc [out] : Pointer to the returned reco context's handle
////////////////////////////////////////////////////////////////////////
HRESULT WINAPI CreateContext(HRECOGNIZER hrec, HRECOCONTEXT *phrc)
{
struct WispContext *pWispContext = NULL;
struct WispRec *pRec;
// Check the recognizer handle
pRec = (struct WispRec*)FindTpgHandle((HANDLE)hrec, TPG_HRECOGNIZER);
if (NULL == pRec)
{
return E_INVALIDARG;
}
// validate the pointer
if (IsBadWritePtr(phrc, sizeof(HRECOCONTEXT)))
{
return E_POINTER;
}
pWispContext = (struct WispContext*)ExternAlloc(sizeof(struct WispContext));
if (!pWispContext)
return E_OUTOFMEMORY;
pWispContext->pGuide = NULL;
pWispContext->pLattice = NULL;
pWispContext->pLatticeProperties = NULL;
pWispContext->pLatticePropertyValues = NULL;
pWispContext->ppLatticeProperties = NULL;
pWispContext->bIsBoxed = FALSE;
pWispContext->bIsCAC = FALSE;
pWispContext->iCACMode = CAC_FULL;
pWispContext->bCACEndInk = FALSE;
pWispContext->uAbort = 0;
pWispContext->ulCurrentStrokeCount = 0;
pWispContext->hrc = NULL;
pWispContext->bHasTextContext = FALSE;
pWispContext->wszBefore = NULL;
pWispContext->wszAfter = NULL;
pWispContext->dwFlags = 0;
pWispContext->wszFactoid = NULL;
// create the handle
*phrc = (HRECOCONTEXT)CreateTpgHandle(TPG_HRECOCONTEXT, pWispContext);
if (NULL == (*phrc))
{
ExternFree(pWispContext);
return E_OUTOFMEMORY;
}
return S_OK;
}
// creates an HRC by calling the appropriate hwx api
HRESULT CreateHRCinContext(struct WispContext *pWispContext)
{
// are we in boxed mode
if (pWispContext->bIsBoxed)
{
pWispContext->hrc = HwxCreate(NULL);
}
// free
else
{
pWispContext->hrc = CreateCompatibleHRC(NULL, NULL);
}
// we failed
if (pWispContext->hrc == NULL)
{
return E_FAIL;
}
// reco settings
if (pWispContext->bHasTextContext)
{
if (!SetHwxCorrectionContext (pWispContext->hrc, pWispContext->wszBefore, pWispContext->wszAfter))
{
return E_FAIL;
}
}
if (!SetHwxFlags(pWispContext->hrc, pWispContext->dwFlags))
{
return E_FAIL;
}
switch (SetHwxFactoid(pWispContext->hrc, pWispContext->wszFactoid))
{
case HRCR_OK:
break;
case HRCR_UNSUPPORTED:
HwxDestroy(pWispContext->hrc);
return TPC_E_INVALID_PROPERTY;
case HRCR_CONFLICT:
HwxDestroy(pWispContext->hrc);
return TPC_E_OUT_OF_ORDER_CALL;
case HRCR_ERROR:
default:
HwxDestroy(pWispContext->hrc);
return E_FAIL;
}
return S_OK;
}
//
// Frees a reco lattice
//
HRESULT FreeRecoLattice(struct WispContext *wisphrc)
{
ULONG i = 0;
RECO_LATTICE *pRecoLattice = wisphrc->pLattice;
if (pRecoLattice == NULL)
{
return S_OK;
}
// Free the Lattice column information
if (pRecoLattice->pLatticeColumns)
{
// Free the array of strokes
if (pRecoLattice->pLatticeColumns[0].pStrokes)
{
ExternFree(pRecoLattice->pLatticeColumns[0].pStrokes);
}
for (i = 0; i < pRecoLattice->ulColumnCount; i++)
{
if (pRecoLattice->pLatticeColumns[i].cpProp.apProps)
{
ExternFree(pRecoLattice->pLatticeColumns[i].cpProp.apProps);
}
}
// Free the array of lattice elements
if (pRecoLattice->pLatticeColumns[0].pLatticeElements)
{
ExternFree(pRecoLattice->pLatticeColumns[0].pLatticeElements);
}
ExternFree(pRecoLattice->pLatticeColumns);
}
// Free the the RecoLattice properties
if (pRecoLattice->pGuidProperties)
{
ExternFree(pRecoLattice->pGuidProperties);
}
// Free the best result information
if (pRecoLattice->pulBestResultColumns)
{
ExternFree(pRecoLattice->pulBestResultColumns);
}
if (pRecoLattice->pulBestResultIndexes)
{
ExternFree(pRecoLattice->pulBestResultIndexes);
}
if (wisphrc->pLatticeProperties)
{
ExternFree(wisphrc->pLatticeProperties);
wisphrc->pLatticeProperties = NULL;
}
if (wisphrc->pLatticePropertyValues)
{
ExternFree(wisphrc->pLatticePropertyValues);
wisphrc->pLatticePropertyValues = NULL;
}
if (wisphrc->ppLatticeProperties != NULL)
{
ExternFree(wisphrc->ppLatticeProperties);
wisphrc->ppLatticeProperties = NULL;
}
// Free the RECO_LATTICE structure
ExternFree(wisphrc->pLattice);
wisphrc->pLattice = NULL;
return S_OK;
}
// DestroyContextInternal
// Destroy a reco context and free the associated memory.
//
// Parameters:
// hrc [in] : pointer to the reco context to destroy
//////////////////////////////////////////////////////////////
HRESULT WINAPI DestroyContextInternal(struct WispContext *wisphrc)
{
HRESULT hr;
// validate and destroy the handle & return the pointer
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
// free the contents of the context
if (wisphrc->hrc)
{
if (wisphrc->bIsBoxed)
HwxDestroy(wisphrc->hrc);
else
DestroyHRC(wisphrc->hrc);
}
if (wisphrc->pGuide)
{
ExternFree(wisphrc->pGuide);
}
if (wisphrc->pLattice)
{
hr = FreeRecoLattice(wisphrc);
ASSERT(SUCCEEDED(hr));
}
wisphrc->pLattice = NULL;
if (wisphrc->bHasTextContext)
{
ExternFree(wisphrc->wszBefore);
ExternFree(wisphrc->wszAfter);
}
ExternFree(wisphrc->wszFactoid);
ExternFree(wisphrc);
return S_OK;
}
// DestroyContext
// Destroy a reco context and free the associated memory.
//
// Parameters:
// hrc [in] : handle to the reco context to destroy
//////////////////////////////////////////////////////////////
HRESULT WINAPI DestroyContext(HRECOCONTEXT hrc)
{
struct WispContext *wisphrc;
// validate and destroy the handle & return the pointer
wisphrc = (struct WispContext*)DestroyTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
return DestroyContextInternal(wisphrc);
}
#ifdef ENABLE_CONFIDENCE_LEVEL
const ULONG PROPERTIES_COUNT = 2;
#else
const ULONG PROPERTIES_COUNT = 1;
#endif
// IRecognizer::GetResultPropertyList
HRESULT WINAPI GetResultPropertyList(HRECOGNIZER hrec, ULONG* pPropertyCount, GUID* pPropertyGuid)
{
HRESULT hr = S_OK;
struct WispRec *pRec;
// Check the recognizer handle
pRec = (struct WispRec*)FindTpgHandle((HANDLE)hrec, TPG_HRECOGNIZER);
if (NULL == pRec)
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pPropertyCount, sizeof(ULONG)))
{
return E_POINTER;
}
if (!pPropertyGuid)
{
*pPropertyCount = PROPERTIES_COUNT; // For now we support only two GUID properties
}
else
{
// Check the array
if (PROPERTIES_COUNT > *pPropertyCount)
{
return TPC_E_INSUFFICIENT_BUFFER;
}
if (IsBadWritePtr(pPropertyGuid, sizeof(GUID)*(*pPropertyCount)))
{
return E_POINTER;
}
pPropertyGuid[0] = GUID_LINEMETRICS;
#ifdef ENABLE_CONFIDENCE_LEVEL
pPropertyGuid[1] = GUID_CONFIDENCELEVEL;
#endif
*pPropertyCount = PROPERTIES_COUNT;
}
return hr;
}
// GetPreferredPacketDescription
// Returns the preferred packet description for the recognizer
// This is going to be x, y only for this recognizer
//
// Parameters:
// hrec [in] : The recognizer we want the preferred
// packet description for
// pPacketDescription [out] : The packet description
/////////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI GetPreferredPacketDescription(HRECOGNIZER hrec , PACKET_DESCRIPTION* pPacketDescription)
{
struct WispRec *pRec;
// Check the recognizer handle
pRec = (struct WispRec*)FindTpgHandle((HANDLE)hrec, TPG_HRECOGNIZER);
if (NULL == pRec)
{
return E_INVALIDARG;
}
// validate the pointer
if (IsBadWritePtr(pPacketDescription, sizeof(PACKET_DESCRIPTION)))
{
return E_POINTER;
}
// We can be called the first time with pPacketProperies
// equal to NULL, just to get the size of those buffer
// The second time we get called thoses buffers are allocated, so
// we can fill them with the data.
if (pPacketDescription->pPacketProperties)
{
// Make sure that the pPacketProperties is of a valid size
// Set the packet size to the size of x and y
pPacketDescription->cbPacketSize = 2 * sizeof(LONG);
// We are only setting 2 properties (X and Y)
if (pPacketDescription->cPacketProperties < 2)
return TPC_E_INSUFFICIENT_BUFFER;
pPacketDescription->cPacketProperties = 2;
// We are not setting buttons
pPacketDescription->cButtons = 0;
// Make sure that the pPacketProperties is of a valid size
if (IsBadWritePtr(pPacketDescription->pPacketProperties, 2 * sizeof(PACKET_PROPERTY)))
{
return E_POINTER;
}
// Fill in pPacketProperies
// Add the GUID_X
pPacketDescription->pPacketProperties[0].guid = g_guidx;
pPacketDescription->pPacketProperties[0].PropertyMetrics = g_DefaultPropMetrics;
// Add the GUID_Y
pPacketDescription->pPacketProperties[1].guid = g_guidy;
pPacketDescription->pPacketProperties[1].PropertyMetrics = g_DefaultPropMetrics;
}
else
{
// Just fill in the PacketDescription structure leavin NULL
// pointers for the pguidButtons and pPacketProperies
// Set the packet size to the size of x and y
pPacketDescription->cbPacketSize = 2*sizeof(LONG);
// We are only setting 2 properties (X and Y)
pPacketDescription->cPacketProperties = 2;
// We are not setting buttons
pPacketDescription->cButtons = 0;
// There are not guid buttons
pPacketDescription->pguidButtons = NULL;
}
return S_OK;
}
#define FUZZ_GEN (1e-9) // general fuzz - nine decimal digits
/**********************************************************************/
// Convert double to int
int RealToInt(double dbl)
{
// Add in the rounding threshold.
// NOTE: The MAXWORD bias used in the floor function
// below must not be combined with this line. If it
// is combined the effect of FUZZ_GEN will be lost.
dbl += 0.5 + FUZZ_GEN;
// Truncate
// The UINT_MAX bias in the floor function will cause
// truncation (rounding toward minuse infinity) within
// the range of a short.
dbl = floor(dbl + UINT_MAX) - UINT_MAX;
// Clip the result.
return dbl > INT_MAX - 7 ? INT_MAX - 7 :
dbl < INT_MIN + 7 ? INT_MIN + 7 : (int)dbl;
}
/**********************************************************************/
// Transform POINT array in place
void Transform(const XFORM *pXf, POINT * pPoints, ULONG cPoints)
{
ULONG iPoint = 0;
LONG xp = 0;
if(NULL != pXf)
{
for(iPoint = 0; iPoint < cPoints; ++iPoint)
{
xp = RealToInt(pPoints[iPoint].x * pXf->eM11 +
pPoints[iPoint].y * pXf->eM21 + pXf->eDx);
pPoints[iPoint].y = RealToInt(pPoints[iPoint].x * pXf->eM12 +
pPoints[iPoint].y * pXf->eM22 + pXf->eDy);
pPoints[iPoint].x = xp;
}
}
}
HRESULT WINAPI AddStroke(HRECOCONTEXT hrc, const PACKET_DESCRIPTION* pPacketDesc, ULONG cbPacket, const BYTE *pPacket, const XFORM *pXForm)
{
HRESULT hr = S_OK;
ULONG ulPointCount = 0;
STROKEINFO stInfo;
POINT *ptArray = NULL;
struct WispContext *wisphrc;
ULONG ulXIndex = 0, ulYIndex = 0;
BOOL bXFound = FALSE, bYFound = FALSE;
ULONG ulPropIndex = 0;
ULONG index = 0;
int hres = 0;
VRC *vrc = NULL;
const LONG* pLongs = (const LONG *)(pPacket);
int temp = 0;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (pPacketDesc != NULL && IsBadReadPtr(pPacketDesc, sizeof(PACKET_DESCRIPTION)))
{
return E_POINTER;
}
if (pXForm != NULL && IsBadReadPtr(pXForm, sizeof(XFORM)))
{
return E_POINTER;
}
// validate the data pointer
if(IsBadReadPtr(pPacket, cbPacket))
{
return E_POINTER;
}
if (!wisphrc->hrc)
{
// If we have a free guide and this is not allowed by
// the recognizer, then fail. Return an out of order
// error because it probably means they forgot to
// set the guide before adding ink.
if (g_pProbTable == NULL && !wisphrc->bIsBoxed)
{
return TPC_E_OUT_OF_ORDER_CALL;
}
hr = CreateHRCinContext(wisphrc);
if (FAILED(hr))
{
return E_FAIL;
}
}
if (wisphrc->bCACEndInk)
{
hr = SetCACMode(hrc, wisphrc->iCACMode);
if (FAILED(hr))
return E_FAIL;
}
vrc = (VRC*)wisphrc->hrc;
// Get the number of packets
if (pPacketDesc)
{
ASSERT(!(cbPacket%(pPacketDesc->cbPacketSize)));
ulPointCount = (cbPacket)/(pPacketDesc->cbPacketSize);
}
else
{
ulPointCount = (cbPacket)/(2*sizeof(LONG));
}
// Fill in the stroke info stucture
// Should check it does not exceed the size of a UINT
stInfo.cPnt = ulPointCount;
// PLEASE FIND ANOTHER WAY TO STORE THE STROKE INDEX!!!
stInfo.dwTick = wisphrc->ulCurrentStrokeCount*60*1000;
stInfo.wPdk = 0x0001;
stInfo.cbPnts = ulPointCount*sizeof(POINT);
wisphrc->ulCurrentStrokeCount++;
// Find the index of GUID_X and GUID_Y
if (pPacketDesc)
{
for (ulPropIndex = 0; ulPropIndex < pPacketDesc->cPacketProperties; ulPropIndex++)
{
if (IsEqualGUID(&(pPacketDesc->pPacketProperties[ulPropIndex].guid), &g_guidx))
{
bXFound = TRUE;
ulXIndex = ulPropIndex;
}
else
if (IsEqualGUID(&(pPacketDesc->pPacketProperties[ulPropIndex].guid), &g_guidy))
{
bYFound = TRUE;
ulYIndex = ulPropIndex;
}
if (bXFound && bYFound)
{
break;
}
}
if (!bXFound || !bYFound)
{
// The coordinates are not part of the packet!
// Remove the last stroke from the stroke array
wisphrc->ulCurrentStrokeCount--;
return TPC_E_INVALID_PACKET_DESCRIPTION;
}
// Allocate the memory for the stroke
// Do it very poorly first (we could reuse the buffer)
ptArray = (POINT*)ExternAlloc(ulPointCount*sizeof(POINT));
if (!ptArray)
{
// Remove the last stroke from the stroke array
wisphrc->ulCurrentStrokeCount--;
return E_OUTOFMEMORY;
}
// Get the points from the packets
for (index = 0; index < ulPointCount; index++, pLongs += (pPacketDesc->cbPacketSize)/sizeof(long))
{
// Feed the ptArray (array of points)
ptArray[index].x = *(pLongs+ulXIndex);
ptArray[index].y = *(pLongs+ulYIndex);
}
// TO DO, for now I transform the points so they
// they are in the ink coordinates. It is up to
// the recognizer team to decide what they should
// use: raw ink or transformed ink
Transform(pXForm, ptArray, ulPointCount);
if (wisphrc->bIsBoxed)
{
if (HwxInput(wisphrc->hrc, ptArray, stInfo.cPnt, stInfo.dwTick))
hres = HRCR_OK;
else
hres = HRCR_ERROR;
}
else
{
hres = AddPenInputHRC(wisphrc->hrc, ptArray, NULL, 0, &stInfo);
}
if ( hres != HRCR_OK)
{
hr = E_FAIL;
// Remove the last stroke from the stroke array
wisphrc->ulCurrentStrokeCount--;
ExternFree(ptArray);
return hr;
}
ExternFree(ptArray);
temp = vrc->pLattice->nRealStrokes;
InterlockedExchange(&(wisphrc->uAbort), temp);
}
else
{
if (wisphrc->bIsBoxed)
{
if (HwxInput(wisphrc->hrc, (POINT*)pPacket, stInfo.cPnt, stInfo.dwTick))
hres = HRCR_OK;
else
hres = HRCR_ERROR;
}
else
{
hres = AddPenInputHRC(wisphrc->hrc, (POINT*)pPacket, NULL, 0, &stInfo);
}
if (hres != HRCR_OK)
{
hr = E_FAIL;
// Remove the last stroke from the stroke array
wisphrc->ulCurrentStrokeCount--;
return hr;
}
temp = vrc->pLattice->nRealStrokes;
InterlockedExchange(&(wisphrc->uAbort), temp);
}
ptArray = NULL;
return hr;
}
HRESULT WINAPI GetBestResultString(HRECOCONTEXT hrc, ULONG *pcwSize, WCHAR* pszBestResult)
{
struct WispContext *wisphrc;
HRESULT hr = S_OK;
VRC *vrc = NULL;
ULONG i = 0;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pcwSize, sizeof(ULONG)))
{
return E_POINTER;
}
// check the string pointer if needed
if ( pszBestResult &&
IsBadWritePtr (pszBestResult, (*pcwSize) * sizeof (*pszBestResult))
)
{
return E_POINTER;
}
vrc = (VRC*)wisphrc->hrc;
if (!vrc)
{
*pcwSize = 0;
return S_OK;
}
if (!vrc->pLatticePath)
{
*pcwSize = 0;
return S_OK;
}
if (!pszBestResult)
{
*pcwSize = vrc->pLatticePath->nChars;
return S_OK;
}
// Make the length realistic
if (*pcwSize > (ULONG)vrc->pLatticePath->nChars)
{
*pcwSize = vrc->pLatticePath->nChars;
}
// Is the buffer too small?
if (*pcwSize < (ULONG)vrc->pLatticePath->nChars)
{
hr = TPC_S_TRUNCATED;
}
for (i = 0; i < *pcwSize; i++)
{
pszBestResult[i] = vrc->pLatticePath->pElem[i].wChar;
}
return hr;
}
//
// GetBestAlternate
//
// This function create the best alternate from the best segmentation
//
// Parameters:
// hrc [in] : the reco context
// pHrcAlt [out] : pointer to the handle of the alternate
/////////////////
HRESULT WINAPI GetBestAlternate(HRECOCONTEXT hrc, HRECOALT* pHrcAlt)
{
struct WispContext *wisphrc;
HRESULT hr = S_OK;
ULONG cbSize = 0;
struct WispAlternate *pWispAlt = NULL;
VRC *vrc = NULL;
ULONG i = 0;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
// First get the number of characters in the string
vrc = (VRC*)wisphrc->hrc;
if (!vrc)
{
return TPC_E_NOT_RELEVANT;
}
if (!vrc->pLatticePath)
{
// There is no ink
return TPC_E_NOT_RELEVANT;
}
cbSize = vrc->pLatticePath->nChars;
// Create the alternate
pWispAlt = (struct WispAlternate*)ExternAlloc(sizeof(struct WispAlternate));
if (!pWispAlt)
{
return E_OUTOFMEMORY;
}
ZeroMemory(pWispAlt, sizeof(struct WispAlternate));
pWispAlt->iNumberOfColumns = cbSize;
pWispAlt->iLength = cbSize;
pWispAlt->OriginalRecoRange.iwcBegin = 0;
pWispAlt->OriginalRecoRange.cCount = cbSize;
pWispAlt->hrc = hrc;
if (cbSize)
{
pWispAlt->pColumnIndex = ExternAlloc(sizeof(ULONG)*cbSize);
if (!pWispAlt->pColumnIndex)
{
ExternFree(pWispAlt);
return E_OUTOFMEMORY;
}
// Initialize the column index array
for (i = 0; i<cbSize; i++)
{
pWispAlt->pColumnIndex[i] = vrc->pLatticePath->pElem[i].iStroke;
}
pWispAlt->pIndexInColumn = ExternAlloc(sizeof(ULONG)*cbSize);
if (!pWispAlt->pIndexInColumn)
{
ExternFree(pWispAlt->pColumnIndex);
ExternFree(pWispAlt);
return E_OUTOFMEMORY;
}
// The best alternate doe not always have the index 0 in the alternate column
// Initialize the index in column array
for (i = 0; i<cbSize; i++)
{
pWispAlt->pIndexInColumn[i] = vrc->pLatticePath->pElem[i].iAlt;
}
}
// create a tpg handle
*pHrcAlt = (HRECOALT)CreateTpgHandle(TPG_HRECOALT, pWispAlt);
if (0 == *pHrcAlt)
{
ExternFree (pWispAlt->pIndexInColumn);
ExternFree (pWispAlt->pColumnIndex);
ExternFree (pWispAlt);
return E_OUTOFMEMORY;
}
return S_OK;
}
// internal implementation: destroy the wispalternate structure
HRESULT DestroyAlternateInternal(struct WispAlternate *wisphrcalt)
{
ExternFree(wisphrcalt->pColumnIndex);
ExternFree(wisphrcalt->pIndexInColumn);
ExternFree(wisphrcalt);
return S_OK;
}
//
// DestroyAlternate
//
// This function destroys an alternate, freeing the allocated memory
//
// Parameters:
// hrcalt [in] : handle of the alternate to be destroyed
/////////////////
HRESULT WINAPI DestroyAlternate(HRECOALT hrcalt)
{
struct WispAlternate *wisphrcalt;
wisphrcalt = (struct WispAlternate *) DestroyTpgHandle (hrcalt, TPG_HRECOALT);
if (NULL == wisphrcalt)
{
return E_INVALIDARG;
}
return DestroyAlternateInternal (wisphrcalt);
}
HRESULT WINAPI SetGuide(HRECOCONTEXT hrc, const RECO_GUIDE* pGuide, ULONG iIndex)
{
struct WispContext *wisphrc;
HWXGUIDE hwxGuide;
HRESULT hr = S_OK;
BOOL bGuideAlreadySet = FALSE;
RECO_GUIDE rgOldGuide;
ULONG uiOldIndex = 0;
BOOL bIsOldGuideBox = FALSE;
BOOL bIsHRCAlreadyCreated = FALSE;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (pGuide != NULL && IsBadReadPtr(pGuide, sizeof(RECO_GUIDE)))
{
return E_POINTER;
}
if (pGuide != NULL)
{
if ((pGuide->cHorzBox < 0 || pGuide->cVertBox < 0) || // invalid
(pGuide->cHorzBox == 0 && pGuide->cVertBox > 0) || // horizontal lined mode
(pGuide->cHorzBox > 0 && pGuide->cVertBox == 0) || // vertical lined mode
(g_pProbTable == NULL && pGuide->cHorzBox == 0 && pGuide->cVertBox == 0)) // free mode not allowed sometimes
{
return E_INVALIDARG;
}
}
if (pGuide == NULL && g_pProbTable == NULL)
{
// Can't do free mode, but got a NULL guide, so return an error.
return E_INVALIDARG;
}
// Is there already an HRC
if (wisphrc->hrc)
{
bIsHRCAlreadyCreated = TRUE;
}
// Save the old values in case the call to the
// recognizer fails
if (wisphrc->pGuide)
{
bGuideAlreadySet = TRUE;
rgOldGuide = *(wisphrc->pGuide);
uiOldIndex = wisphrc->uiGuideIndex;
bIsOldGuideBox = wisphrc->bIsBoxed;
}
// If there was no guide already present, allocate one
if (!wisphrc->pGuide)
wisphrc->pGuide = ExternAlloc(sizeof(RECO_GUIDE));
if (!wisphrc->pGuide)
return E_OUTOFMEMORY;
// If the guide is NULL, then treat it as all zeros (free mode)
if (pGuide != NULL)
{
*(wisphrc->pGuide) = *pGuide;
}
else
{
ZeroMemory(wisphrc->pGuide, sizeof(RECO_GUIDE));
}
wisphrc->uiGuideIndex = iIndex;
// Check if we are in box mode or free input mode
if (wisphrc->pGuide->cHorzBox && wisphrc->pGuide->cVertBox)
{
// We are in the box api mode
// We need to have a proper conversion
ZeroMemory(&hwxGuide, sizeof(HWXGUIDE));
hwxGuide.cHorzBox = wisphrc->pGuide->cHorzBox;
hwxGuide.cVertBox = wisphrc->pGuide->cVertBox;
hwxGuide.cxBox = wisphrc->pGuide->cxBox;
hwxGuide.cyBox = wisphrc->pGuide->cyBox;
hwxGuide.xOrigin = wisphrc->pGuide->xOrigin;
hwxGuide.yOrigin = wisphrc->pGuide->yOrigin;
hwxGuide.cxOffset = wisphrc->pGuide->cxBase ;
hwxGuide.cyOffset = 0;
hwxGuide.cxWriting = wisphrc->pGuide->cxBox - (2 * wisphrc->pGuide->cxBase) ;
if (wisphrc->pGuide->cyBase > 0) {
hwxGuide.cyWriting = wisphrc->pGuide->cyBase ;
} else {
hwxGuide.cyWriting = wisphrc->pGuide->cyBox ;
}
hwxGuide.cyMid = 0 ;
hwxGuide.cyBase = 0 ;
hwxGuide.nDir = HWX_HORIZONTAL ;
// Is the hrc already created
if (bIsHRCAlreadyCreated)
{
// Are we already in box mode?
if (!wisphrc->bIsBoxed)
{
// We need to switch to a box hrc if possible
if (wisphrc->ulCurrentStrokeCount == 0)
{
// Destroy the previous context
DestroyHRC(wisphrc->hrc);
wisphrc->hrc = NULL;
}
else
{
hr = E_FAIL;
}
}
}
wisphrc->bIsBoxed = TRUE;
if (SUCCEEDED(hr) && !wisphrc->hrc)
{
hr = CreateHRCinContext(wisphrc);
if (FAILED(hr))
hr = E_FAIL;
}
if (SUCCEEDED(hr))
{
if (HwxSetGuide(wisphrc->hrc, &hwxGuide))
{
if (TRUE == HwxSetAbort(wisphrc->hrc, &(wisphrc->uAbort)))
{
return S_OK;
}
else
{
hr = E_FAIL;
}
}
else
{
hr = E_INVALIDARG;
}
}
}
else
{
wisphrc->bIsBoxed = FALSE;
if (!wisphrc->hrc)
{
// We need to switch to a free hrc if possible
if (wisphrc->ulCurrentStrokeCount == 0)
{
// Destroy the previous context
HwxDestroy(wisphrc->hrc);
wisphrc->hrc = NULL;
}
else
{
hr = E_FAIL;
}
}
hr = CreateHRCinContext(wisphrc);
if (FAILED(hr))
hr = E_FAIL;
// we are in the free api mode
if (SUCCEEDED(hr))
{
if (HRCR_OK == SetGuideHRC(wisphrc->hrc, (GUIDE *)wisphrc->pGuide, iIndex))
return S_OK;
hr = E_INVALIDARG;
}
}
// The calls did not succeed.
// If we allocated an hrc, destroy it
if (!bIsHRCAlreadyCreated && wisphrc->hrc)
{
if (wisphrc->bIsBoxed)
{
HwxDestroy(wisphrc->hrc);
}
else
{
DestroyHRC(wisphrc->hrc);
}
wisphrc->hrc = NULL;
}
// Set back the old guide
if (bGuideAlreadySet)
{
*(wisphrc->pGuide) = rgOldGuide;
wisphrc->bIsBoxed = bIsOldGuideBox;
wisphrc->uiGuideIndex = uiOldIndex;
}
else
{
ExternFree(wisphrc->pGuide);
wisphrc->pGuide = NULL;
wisphrc->bIsBoxed = FALSE;
}
return hr;
}
HRESULT WINAPI GetGuide(HRECOCONTEXT hrc, RECO_GUIDE* pGuide, ULONG *piIndex)
{
struct WispContext *wisphrc;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pGuide, sizeof(RECO_GUIDE)))
{
return E_POINTER;
}
if (IsBadWritePtr(piIndex, sizeof(ULONG)))
{
return E_POINTER;
}
if (!wisphrc->pGuide)
{
return S_FALSE;
}
if (wisphrc->pGuide)
{
*pGuide = *(wisphrc->pGuide);
}
if (piIndex)
{
*piIndex = wisphrc->uiGuideIndex;
}
return S_OK;
}
HRESULT WINAPI AdviseInkChange(HRECOCONTEXT hrc, BOOL bNewStroke)
{
struct WispContext *wisphrc;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
InterlockedIncrement(&(wisphrc->uAbort));
return S_OK;
}
HRESULT WINAPI SetCACMode(HRECOCONTEXT hrc, int iMode)
{
HRESULT hr = S_OK;
struct WispContext *wisphrc;
VRC *vrc;
HRECOCONTEXT CloneHrc = NULL;
HRC OldHrc = NULL;
int i = 0, j = 0;
int iCACMode = 0;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (!wisphrc->bIsBoxed)
{
return E_FAIL;
}
if (iMode != CAC_FULL && iMode != CAC_PREFIX && iMode != CAC_RANDOM)
{
return E_INVALIDARG;
}
vrc = (VRC*)wisphrc->hrc;
OldHrc = wisphrc->hrc;
wisphrc->hrc = NULL;
// Create the new context
wisphrc->hrc = HwxCreate(OldHrc);
if (!wisphrc->hrc)
{
wisphrc->hrc = OldHrc;
return E_FAIL;
}
if (FALSE == HwxSetAbort(wisphrc->hrc, &(wisphrc->uAbort)))
{
ASSERT(0);
}
// Set the CAC mode
if (iMode == CAC_FULL)
{
iCACMode = HWX_PARTIAL_ALL;
}
else
if (iMode == CAC_PREFIX)
{
iCACMode = HWX_PARTIAL_ORDER;
}
else
if (iMode == CAC_RANDOM)
{
iCACMode = HWX_PARTIAL_FREE;
}
if (!HwxSetPartial(wisphrc->hrc, iCACMode))
{
// Put things back together
HwxDestroy(wisphrc->hrc);
wisphrc->hrc = ((struct WispContext*)OldHrc)->hrc;
return E_FAIL;
}
wisphrc->bIsCAC = TRUE;
wisphrc->iCACMode = iMode;
wisphrc->bCACEndInk = FALSE;
// TO DO
// TO DO
//
// We probably need to store the original ink, not use the smoothed and merged ink that
// is store in the Lattice...
// We need to get the ink from the old context, if there was an old context
if (vrc != NULL)
{
for (i = 0; i < vrc->pLattice->nStrokes; i++)
{
// We need to reorder the strokes to have them in the same order
for (j = 0; j < vrc->pLattice->nStrokes; j++)
{
if (vrc->pLattice->pStroke[j].iOrder == i)
{
// Add the Stroke to the new context
if (!HwxInput(wisphrc->hrc, vrc->pLattice->pStroke[j].pts, vrc->pLattice->pStroke[j].nInk, vrc->pLattice->pStroke[j].timeStart))
{
hr = E_FAIL;
}
break;
}
}
}
wisphrc->uAbort = vrc->pLattice->nStrokes;
if (vrc->fBoxedInput)
HwxDestroy(OldHrc);
else
DestroyHRC(OldHrc);
}
else
{
wisphrc->uAbort = 0;
}
return hr;
}
HRESULT WINAPI EndInkInput(HRECOCONTEXT hrc)
{
struct WispContext *wisphrc;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (wisphrc->bIsBoxed)
{
if (HwxEndInput(wisphrc->hrc))
return S_OK;
}
else
{
if (HRCR_OK == EndPenInputHRC(wisphrc->hrc))
return S_OK;
}
if (!wisphrc->ulCurrentStrokeCount)
{
return S_OK; // We do not have ink yet
}
return E_FAIL;
}
// Given a recognition context, create a new one which has no ink in it, but
// is otherwise identical. An error is returned if there are any allocation
// problems (which should be the only types of errors).
HRESULT WINAPI CloneContext(HRECOCONTEXT hrc, HRECOCONTEXT* pCloneHrc)
{
struct WispContext *pWispContext = NULL;
struct WispContext *wisphrc;
HRESULT hRes = S_OK, hr = S_OK;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pCloneHrc, sizeof(HRECOCONTEXT)))
{
return E_POINTER;
}
pWispContext = (struct WispContext*)ExternAlloc(sizeof(struct WispContext));
if (!pWispContext)
{
return E_OUTOFMEMORY;
}
// Did we already create a context???
if (!wisphrc->hrc)
{
// The context was not already created
memcpy(pWispContext, wisphrc, sizeof(struct WispContext));
// If a guide was created, then we would have a context
ASSERT(!wisphrc->pGuide);
pWispContext->pGuide = NULL;
// You can't get a lattice until after processing has been done (in a context)
ASSERT(!wisphrc->pLattice);
pWispContext->pLattice = NULL;
pWispContext->pLatticeProperties = NULL;
pWispContext->pLatticePropertyValues = NULL;
pWispContext->ppLatticeProperties = NULL;
// Copy the text context
if (wisphrc->bHasTextContext)
{
pWispContext->bHasTextContext = TRUE;
pWispContext->wszBefore = Externwcsdup(wisphrc->wszBefore);
pWispContext->wszAfter = Externwcsdup(wisphrc->wszAfter);
if (pWispContext->wszBefore == NULL || pWispContext->wszAfter == NULL)
{
ExternFree(pWispContext->wszBefore);
ExternFree(pWispContext->wszAfter);
ExternFree(pWispContext);
return E_OUTOFMEMORY;
}
}
else
{
pWispContext->bHasTextContext = FALSE;
pWispContext->wszBefore = NULL;
pWispContext->wszAfter = NULL;
}
// Copy factoid setting
if (wisphrc->wszFactoid)
{
pWispContext->wszFactoid = Externwcsdup(wisphrc->wszFactoid);
if (pWispContext->wszFactoid == NULL)
{
ExternFree(pWispContext->wszAfter);
ExternFree(pWispContext->wszBefore);
ExternFree(pWispContext);
return E_OUTOFMEMORY;
}
}
else
{
pWispContext->wszFactoid = NULL;
}
}
else
{
// Depending of whether we are in box mode create the hwx hrc
if (!wisphrc->bIsBoxed)
{
pWispContext->bIsBoxed = FALSE;
pWispContext->hrc = CreateCompatibleHRC(wisphrc->hrc, NULL);
}
else
{
pWispContext->bIsBoxed = TRUE;
pWispContext->hrc = HwxCreate(wisphrc->hrc);
}
if (!pWispContext->hrc)
{
hr = E_OUTOFMEMORY;
}
// Set the context variables
if (SUCCEEDED(hr) && wisphrc->bHasTextContext)
{
pWispContext->bHasTextContext = TRUE;
pWispContext->wszBefore = Externwcsdup(wisphrc->wszBefore);
pWispContext->wszAfter = Externwcsdup(wisphrc->wszAfter);
if (pWispContext->wszBefore == NULL || pWispContext->wszAfter == NULL)
{
hr = E_OUTOFMEMORY;
}
}
else
{
pWispContext->bHasTextContext = FALSE;
pWispContext->wszBefore = NULL;
pWispContext->wszAfter = NULL;
}
// Copy flags
pWispContext->dwFlags = wisphrc->dwFlags;
// Copy factoid setting
if (SUCCEEDED(hr) && wisphrc->wszFactoid)
{
pWispContext->wszFactoid = Externwcsdup(wisphrc->wszFactoid);
if (pWispContext->wszFactoid == NULL)
{
hr = E_OUTOFMEMORY;
}
}
else
{
pWispContext->wszFactoid = NULL;
}
// Set the guide for the Wisp structure
if (SUCCEEDED(hr) && wisphrc->pGuide)
{
pWispContext->pGuide = ExternAlloc(sizeof(RECO_GUIDE));
if (!pWispContext->pGuide)
{
hr = E_OUTOFMEMORY;
}
else
{
*(pWispContext->pGuide) = *(wisphrc->pGuide);
pWispContext->uiGuideIndex = wisphrc->uiGuideIndex;
}
}
else
{
pWispContext->pGuide = NULL;
}
// Set the abort for hwx
pWispContext->uAbort = 0;
if (SUCCEEDED(hr) && pWispContext->bIsBoxed)
{
if (!HwxSetAbort(pWispContext->hrc, &(pWispContext->uAbort)))
{
hr = E_FAIL;
}
}
pWispContext->ulCurrentStrokeCount = 0;
pWispContext->bCACEndInk = FALSE;
pWispContext->bIsCAC = FALSE;
// Set the CAC Mode
if (SUCCEEDED(hr) && wisphrc->bIsCAC)
{
pWispContext->bIsCAC = TRUE;
pWispContext->iCACMode = wisphrc->iCACMode;
}
}
// Clean the lattice
pWispContext->pLattice = NULL;
pWispContext->pLatticeProperties = NULL;
pWispContext->pLatticePropertyValues = NULL;
pWispContext->ppLatticeProperties = NULL;
if (SUCCEEDED(hr))
{
// create a tpg handle
*pCloneHrc = (HRECOCONTEXT)CreateTpgHandle(TPG_HRECOCONTEXT, pWispContext);
if (NULL == (*pCloneHrc))
{
hr = E_OUTOFMEMORY;
}
}
if (!SUCCEEDED(hr))
{
hRes = DestroyContextInternal(pWispContext);
ASSERT(SUCCEEDED(hRes));
}
return hr;
}
// ResetContext
// This function keeps the settings on the passed reco context
// but purges it of the ink it contains. If the EndInkInput
// had been called on the reco context, Reset context will
// now allow more ink to be entered.
//
// Parameter:
// hrc [in] : the handle to the reco context
/////////////////////////////////////////////////////////
HRESULT WINAPI ResetContext(HRECOCONTEXT hrc)
{
struct WispContext *wisphrc;
HRESULT hr = S_OK;
HRC hrcold = NULL;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (!wisphrc->hrc)
{
return S_OK;
}
// Save the old HRC (in case of an error), and put in the new one
hrcold = wisphrc->hrc;
if (!wisphrc->bIsBoxed)
{
wisphrc->hrc = CreateCompatibleHRC(wisphrc->hrc, NULL);
}
else
{
wisphrc->hrc = HwxCreate(wisphrc->hrc);
}
if (!wisphrc->hrc)
{
wisphrc->hrc = hrcold;
return E_FAIL;
}
// If there was a guide, put it back
if (SUCCEEDED(hr) && wisphrc->pGuide)
{
hr = SetGuide(hrc, wisphrc->pGuide, wisphrc->uiGuideIndex);
}
if (SUCCEEDED(hr) && wisphrc->bIsCAC)
{
hr = SetCACMode(hrc, wisphrc->iCACMode);
}
if (SUCCEEDED(hr) && wisphrc->bHasTextContext)
{
hr = SetTextContext(hrc,
wcslen(wisphrc->wszBefore), wisphrc->wszBefore,
wcslen(wisphrc->wszAfter), wisphrc->wszAfter);
}
if (SUCCEEDED(hr))
{
hr = SetFlags(hrc, wisphrc->dwFlags);
}
if (SUCCEEDED(hr))
{
if (wisphrc->wszFactoid)
hr = SetFactoid(hrc, wcslen(wisphrc->wszFactoid), wisphrc->wszFactoid);
else
hr = SetFactoid(hrc, 0, wisphrc->wszFactoid);
}
if (FAILED(hr))
{
// Something went wrong. Restore the context to its original state.
if (!wisphrc->bIsBoxed)
{
DestroyHRC(wisphrc->hrc);
}
else
{
HwxDestroy(wisphrc->hrc);
}
wisphrc->hrc = hrcold;
return hr;
}
// These changes are done last, because they can't be undone easily.
// All error cases have already been taken care of above.
wisphrc->ulCurrentStrokeCount = 0;
wisphrc->uAbort = 0;
wisphrc->bCACEndInk = FALSE;
if (wisphrc->pLattice)
{
hr = FreeRecoLattice(wisphrc);
}
wisphrc->pLattice = NULL;
if (!wisphrc->bIsBoxed)
{
DestroyHRC(hrcold);
}
else
{
HwxDestroy(hrcold);
}
return hr;
}
// Sets the prefix and suffix context for the recognition context. Can
// return errors on memory allocation failure. Note that this function
// is called with the strings pointing at the strings already in the HRC,
// so we need to be careful not to free the old strings before copying them.
HRESULT WINAPI SetTextContext(HRECOCONTEXT hrc, ULONG cwcBefore, const WCHAR *pwcBefore, ULONG cwcAfter, const WCHAR *pwcAfter)
{
HRESULT hr = S_OK;
struct WispContext *wisphrc;
WCHAR *wszBefore, *wszAfter;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if ( IsBadReadPtr(pwcBefore, cwcBefore * sizeof(WCHAR)) ||
IsBadReadPtr(pwcAfter, cwcAfter * sizeof(WCHAR))
)
{
return E_POINTER;
}
wszBefore = ExternAlloc((cwcBefore + 1) * sizeof(WCHAR));
if (wszBefore == NULL)
{
return E_OUTOFMEMORY;
}
wszAfter = ExternAlloc((cwcAfter + 1) * sizeof(WCHAR));
if (wszAfter == NULL)
{
ExternFree(wszBefore);
return E_OUTOFMEMORY;
}
memcpy(wszBefore, pwcBefore, cwcBefore * sizeof(WCHAR));
wszBefore[cwcBefore] = 0;
memcpy(wszAfter, pwcAfter, cwcAfter * sizeof(WCHAR));
wszAfter[cwcAfter] = 0;
// If we have a context already, then try to set this context.
// The only errors are memory allocation errors, so we don't need
// to create a context here to make sure the call will succeed.
if (wisphrc->hrc)
{
if (!SetHwxCorrectionContext(wisphrc->hrc, wszBefore, wszAfter))
{
hr = E_FAIL;
}
}
// If everything went okay, then we can update the context.
if (SUCCEEDED(hr))
{
wisphrc->bHasTextContext = TRUE;
ExternFree(wisphrc->wszBefore);
ExternFree(wisphrc->wszAfter);
wisphrc->wszBefore = wszBefore;
wisphrc->wszAfter = wszAfter;
}
return hr;
}
// Create an alternate (returned by setting the pointer ppAlt). The contents of
// the alternate are determined by pAltStruct and pdbList.
HRESULT CreateDifBreakAlternate(DifBreakList* pdbList, DifBreakAltStruct *pAltStruct, struct WispAlternate **ppAlt)
{
int i = 0;
VRC *vrc = pAltStruct->vrc;
DiffBreakElement *pCur = NULL;
*ppAlt = (struct WispAlternate*)ExternAlloc(sizeof(struct WispAlternate));
if (!*ppAlt)
return E_OUTOFMEMORY;
ZeroMemory(*ppAlt, sizeof(struct WispAlternate));
// Initialize the new alternate structure
(*ppAlt)->iLength = (*ppAlt)->iNumberOfColumns = pdbList->iColumnCount;
(*ppAlt)->pColumnIndex = (int*)ExternAlloc(sizeof(int)*(*ppAlt)->iNumberOfColumns);
if (!(*ppAlt)->pColumnIndex)
{
ExternFree(*ppAlt);
return E_OUTOFMEMORY;
}
(*ppAlt)->pIndexInColumn = (int*)ExternAlloc(sizeof(int)*(*ppAlt)->iNumberOfColumns);
if (!(*ppAlt)->pIndexInColumn)
{
ExternFree((*ppAlt)->pColumnIndex);
ExternFree(*ppAlt);
return E_OUTOFMEMORY;
}
(*ppAlt)->OriginalRecoRange.iwcBegin = pAltStruct->iFirstChar;
(*ppAlt)->OriginalRecoRange.cCount = pAltStruct->iLastChar -
pAltStruct->iFirstChar + 1;
pCur = pdbList->pFirst;
for (i = 0; i < pdbList->iColumnCount; i++)
{
// Add the ColumnIndex
(*ppAlt)->pColumnIndex[i] = pCur->iColumn;
(*ppAlt)->pIndexInColumn[i] = pCur->iIndex;
pCur = pCur->pNext;
}
return S_OK;
}
BOOL AddToDefSegList(DifBreakList* pdbList, DifBreakAltStruct *pAltStruct)
{
AltRank *pAltRank = NULL;
HRESULT hr = S_OK, hRes = S_OK;
AltRankList *pAltRankList = pAltStruct->paltRankList;
AltRank *pPrev = NULL, *pCur;
UINT i = 0;
DiffBreakElement *pCurrent = NULL;
int j = 0;
// Doesn't make sense to add alternates to a list when no alternates are allowed.
ASSERT(pAltStruct->ulMax > 0);
if (pAltStruct->ulMax == 0)
{
return TRUE;
}
// Is the score even interesting?
if (pAltRankList->ulSize == pAltStruct->ulMax &&
!pdbList->bCurrentPath &&
pAltRankList->pLast != NULL &&
pAltRankList->pLast->fScore >= pdbList->score)
return TRUE;
// Is the decomposition interesting (depending on the recognition mode)
// For now yes, everyting is interesting!
// Create the alternate
pAltRank = (AltRank*)ExternAlloc(sizeof(AltRank));
if (!pAltRank)
return FALSE;
pAltRank->fScore = pdbList->score;
// All paths created here are not on the current path
pAltRank->bCurrentPath = pdbList->bCurrentPath;
pAltRank->next = NULL;
// Add the new alternate at the current location
hr = CreateDifBreakAlternate(pdbList, pAltStruct, &(pAltRank->wispalt));
if (FAILED(hr))
{
ExternFree(pAltRank);
return FALSE;
}
if (!pAltRankList->pFirst)
{
// Add at the start of the location
pAltRankList->pFirst = pAltRank;
pAltRankList->pLast = pAltRank;
pAltRankList->ulSize = 1;
return TRUE;
}
// If the new alternate is the current path, then it goes to the top of the list.
// If not, and the current top of list is not on the current path, then compare scores.
if (pdbList->bCurrentPath ||
(!pAltRankList->pFirst->bCurrentPath && pAltRankList->pFirst->fScore < pdbList->score))
{
// Add at the start of the location
pAltRank->next = pAltRankList->pFirst;
pAltRankList->pFirst = pAltRank;
if (pAltRankList->ulSize == pAltStruct->ulMax)
{
// Delete the last element
hRes = DestroyAlternateInternal(pAltRankList->pLast->wispalt);
ASSERT(SUCCEEDED(hRes));
ExternFree(pAltRankList->pLast);
// Get a pointer to the last element
pCur = pAltRankList->pFirst;
while(pCur->next != pAltRankList->pLast)
pCur = pCur->next;
pAltRankList->pLast = pCur;
pCur->next = NULL;
}
else
{
pAltRankList->ulSize++;
}
return TRUE;
}
pCur = pAltRankList->pFirst;
// Insert the link at the right location
for (i = 0; i < pAltRankList->ulSize - 1; i++)
{
pPrev = pCur;
pCur = pCur->next;
if (pCur->fScore < pdbList->score)
{
// insert at the pPrev
pAltRank->next = pCur;
pPrev->next = pAltRank;
if (pAltRankList->ulSize == pAltStruct->ulMax)
{
// Delete the last element
HRESULT hrDA = DestroyAlternateInternal(pAltRankList->pLast->wispalt);
ASSERT(SUCCEEDED(hrDA));
ExternFree(pAltRankList->pLast);
// Get a pointer to the last element
pCur = pAltRankList->pFirst;
while(pCur->next != pAltRankList->pLast)
pCur = pCur->next;
pAltRankList->pLast = pCur;
pCur->next = NULL;
}
else
{
pAltRankList->ulSize++;
}
return TRUE;
}
}
// We are actually adding at the end of the list
pAltRank->next = NULL;
pAltRankList->pLast->next = pAltRank;
pAltRankList->pLast = pAltRank;
pAltRankList->ulSize++; // obviously we still have room
return TRUE;
}
/*
static float GetScore(LATTICE *pLattice, int iStroke, int iAlt)
{
if (pLattice->fUseGuide)
{
return pLattice->pAltList[iStroke].alts[iAlt].logProb;
}
else
{
return pLattice->pAltList[iStroke].alts[iAlt].logProb * pLattice->pAltList[iStroke].alts[iAlt].nStrokes;
}
}
*/
BOOL GetRecDifSegAltList(int iCurrentStroke, int iCurrentIndex, DifBreakList* pdbList, DifBreakAltStruct *pAltStruct)
{
int iNextStroke = 0;
int i = 0, j = 0, l = 0;
DiffBreakElement dbElement;
DiffBreakElement dbSpaceElement;
float fOriginalScore = pdbList->score;
BOOL bOriginalCurrentPath = pdbList->bCurrentPath;
BOOL bSomethingAdded = FALSE;
BOOL bMainSeg = FALSE;
int iNumberOfStrokes = 0;
BOOL bAllBreakSkip = FALSE;
int iNextNextStroke = 0;
BOOL bSameBreak = FALSE;
BOOL bOkay = TRUE;
iNextStroke = iCurrentStroke -
pAltStruct->vrc->pLattice->pAltList[iCurrentStroke].alts[iCurrentIndex].nStrokes;
// Check if we are at the end (we include uiFirstIndex)
if (pAltStruct->iMode == LARGE_BREAKS)
{
if (pAltStruct->vrc->pLattice->pAltList[iCurrentStroke].alts[iCurrentIndex].nStrokes
> iCurrentStroke-pAltStruct->iFirstStroke)
{
// Yes this is a last (or rather "first") stroke
// But does this stroke correspond to the start of a stroke from the main
// segmentation?
bMainSeg = FALSE;
for (j = pAltStruct->iLastChar; j>=0; j--)
{
if (pAltStruct->vrc->pLatticePath->pElem[j].iStroke -
pAltStruct->vrc->pLatticePath->pElem[j].nStrokes ==
iNextStroke)
{
bMainSeg = TRUE;
pAltStruct->iFirstChar = j;
break;
}
}
// Add this to the stroke list
if (bMainSeg)
return AddToDefSegList(pdbList, pAltStruct);
}
}
else
{
if (pAltStruct->vrc->pLattice->pAltList[iCurrentStroke].alts[iCurrentIndex].nStrokes
== iCurrentStroke-pAltStruct->iFirstStroke+1)
{
// We are at the end
for (j = pAltStruct->iLastChar; j>=0; j--)
{
if (pAltStruct->vrc->pLatticePath->pElem[j].iStroke -
pAltStruct->vrc->pLatticePath->pElem[j].nStrokes ==
iNextStroke)
{
pAltStruct->iFirstChar = j;
return AddToDefSegList(pdbList, pAltStruct);
}
}
// This is an error case
return FALSE;
}
if (pAltStruct->vrc->pLattice->pAltList[iCurrentStroke].alts[iCurrentIndex].nStrokes
> iCurrentStroke-pAltStruct->iFirstStroke+1)
{
// Not an error, we just stepped back too far in the lattice.
return TRUE;
}
}
// We are not at the end (or start) of the alternate, dig deeper
// First, see if we need a space
if (pAltStruct->vrc->pLattice->pAltList[iNextStroke].fSpaceAfterStroke)
{
dbSpaceElement.iColumn = iNextStroke;
dbSpaceElement.iIndex = SPACE_ALT_ID;
dbSpaceElement.pNext = pdbList->pFirst;
pdbList->iColumnCount++;
pdbList->pFirst = &dbSpaceElement;
}
// Then add on the placeholder for the current character
dbElement.iColumn = iNextStroke;
dbElement.pNext = pdbList->pFirst;
pdbList->iColumnCount++;
pdbList->pFirst = &dbElement;
// In the case of ALT_BREAKS_SAME, get the number of strokes of the best result's column
if (pAltStruct->iMode == ALT_BREAKS_SAME)
{
iNumberOfStrokes = -1;
for (i = 0; i < pAltStruct->vrc->pLattice->pAltList[iNextStroke].nUsed; i++)
{
if (pAltStruct->vrc->pLattice->pAltList[iNextStroke].alts[i].fCurrentPath)
{
iNumberOfStrokes = pAltStruct->vrc->pLattice->pAltList[iNextStroke].alts[i].nStrokes;
break;
}
}
ASSERT(iNumberOfStrokes>0);
// If we don't find the current path, something has gone wrong. The
// rest of the code will behave sensibly, though, so continue.
}
for (i = 0; i < pAltStruct->vrc->pLattice->pAltList[iNextStroke].nUsed; i++)
{
// TBD:
// Here we should have an optimization to know if
// we should continue processing the alternates with the
// same decomposition
if (pAltStruct->iMode == ALT_BREAKS_SAME)
if (pAltStruct->vrc->pLattice->pAltList[iNextStroke].alts[i].nStrokes != iNumberOfStrokes)
continue;
// If we have been on the current path so far and are still on it with this
// node, then we are staying on the current path
pdbList->bCurrentPath = bOriginalCurrentPath &&
pAltStruct->vrc->pLattice->pAltList[iNextStroke].alts[i].fCurrentPath;
// Only need to skip alternates if we are trying to get one of each
// segmentation. And we never need to skip the current path, since we
// always want to return that segmentation.
if (pAltStruct->iMode == ALT_BREAKS_UNIQUE && !pdbList->bCurrentPath)
{
bAllBreakSkip = FALSE;
// Did we already go over an alternate with the same number of strokes?
for (l = 0; l<i; l++)
{
if (pAltStruct->vrc->pLattice->pAltList[iNextStroke].alts[i].nStrokes ==
pAltStruct->vrc->pLattice->pAltList[iNextStroke].alts[l].nStrokes)
{
bAllBreakSkip = TRUE;
break;
}
}
if (bAllBreakSkip)
continue;
// If we have been on the current path so far, but are now considering a
// character off the current path,
// then skip it if there is a currrent path character later in the alt
// list with the same number of strokes.
if (!pdbList->bCurrentPath && bOriginalCurrentPath)
{
for (l = i + 1; l < pAltStruct->vrc->pLattice->pAltList[iNextStroke].nUsed; l++)
{
if (pAltStruct->vrc->pLattice->pAltList[iNextStroke].alts[l].fCurrentPath &&
pAltStruct->vrc->pLattice->pAltList[iNextStroke].alts[i].nStrokes ==
pAltStruct->vrc->pLattice->pAltList[iNextStroke].alts[l].nStrokes)
{
bAllBreakSkip = TRUE;
break;
}
}
}
if (bAllBreakSkip) continue;
}
dbElement.iIndex = i;
pdbList->score = fOriginalScore +
pAltStruct->vrc->pLattice->pAltList[iNextStroke].alts[i].logProb;
// GetScore(pAltStruct->vrc->pLattice, iNextStroke, i);
if (!GetRecDifSegAltList(iNextStroke, i, pdbList, pAltStruct))
bOkay = FALSE;
}
pdbList->iColumnCount--;
pdbList->pFirst = dbElement.pNext;
// Unwind the space if necessary
if (pAltStruct->vrc->pLattice->pAltList[iNextStroke].fSpaceAfterStroke)
{
pdbList->iColumnCount--;
pdbList->pFirst = dbSpaceElement.pNext;
}
pdbList->score = fOriginalScore;
pdbList->bCurrentPath = bOriginalCurrentPath;
return bOkay;
}
HRESULT GetDifSegAltList(VRC *vrc, int iLastStroke, int iFirstStroke, ULONG ulMax, AltRankList *pAltRankList, int iMode, int iFirstChar, int iLastChar)
{
HRESULT hr = S_OK;
int iStroke = 0;
int i = 0, j = 0, l = 0;
DifBreakList dbList;
DiffBreakElement dbElement;
BOOL bGoodStart = FALSE;
BOOL bAllBreakSkip = FALSE;
DifBreakAltStruct altStruct;
int iNumberOfStrokes = 0;
// Get the last Column alternates, they should contain uiLastStroke
// For each of these alternate, get the complete alternate list, stopping
// at uiFirstStroke.
// Initialize the data
altStruct.iFirstStroke = iFirstStroke;
altStruct.iFirstChar = iFirstChar;
altStruct.iLastChar = iLastChar;
altStruct.iMode = iMode;
altStruct.ulMax = ulMax;
altStruct.vrc = vrc;
altStruct.paltRankList = pAltRankList;
altStruct.paltRankList->pFirst = altStruct.paltRankList->pLast = NULL;
altStruct.paltRankList->ulSize = 0;
dbList.iColumnCount = 1;
dbList.pFirst = &dbElement;
dbList.score = 0.0;
// The starting last stroke should no be further away than 35 strokes from
// the uiLastStroke
if (iMode == LARGE_BREAKS)
iStroke = (vrc->pLattice->nStrokes > iLastStroke + 35 ? iLastStroke + 35 : vrc->pLattice->nStrokes - 1);
else
iStroke = iLastStroke;
while (iStroke >= iLastStroke)
{
// The stroke has to be one of the main decomposition
if (iMode == LARGE_BREAKS)
{
bGoodStart = FALSE;
for (i = 0; i < vrc->pLattice->pAltList[iStroke].nUsed; i++)
{
if (vrc->pLattice->pAltList[iStroke].alts[i].fCurrentPath)
{
bGoodStart = TRUE;
// Get the character number in the best alternate string
for (j = 0; j < vrc->pLatticePath->nChars; j++)
{
if (vrc->pLatticePath->pElem[j].iStroke == iStroke)
{
altStruct.iLastChar = j;
break;
}
}
break;
}
}
}
else
{
altStruct.iLastChar = iLastChar;
bGoodStart = TRUE;
}
if (bGoodStart)
{
// In the case of ALT_BREAKS_SAME, get the number of strokes of the best result's column
if (iMode == ALT_BREAKS_SAME)
{
iNumberOfStrokes = -1;
for (i = 0; i < vrc->pLattice->pAltList[iStroke].nUsed; i++)
{
if (vrc->pLattice->pAltList[iStroke].alts[i].fCurrentPath)
{
iNumberOfStrokes = vrc->pLattice->pAltList[iStroke].alts[i].nStrokes;
break;
}
}
ASSERT(iNumberOfStrokes>0);
if (iNumberOfStrokes <= 0)
hr = E_UNEXPECTED;
}
// Search if there is an alternate that contains uiLastStroke
for (i = 0; i < vrc->pLattice->pAltList[iStroke].nUsed; i++)
{
if (iMode == ALT_BREAKS_SAME)
if (vrc->pLattice->pAltList[iStroke].alts[i].nStrokes != iNumberOfStrokes)
continue;
if (iMode == ALT_BREAKS_UNIQUE && !vrc->pLattice->pAltList[iStroke].alts[i].fCurrentPath)
{
// Did we already go over an alternate with the same number of strokes?
bAllBreakSkip = FALSE;
for (l = 0; l<i; l++)
{
if (vrc->pLattice->pAltList[iStroke].alts[i].nStrokes ==
vrc->pLattice->pAltList[iStroke].alts[l].nStrokes)
{
bAllBreakSkip = TRUE;
break;
}
}
if (bAllBreakSkip) continue;
// If we are considering a character which is not on the current path,
// then skip it if there is a current path character later in the alt
// list with the same number of strokes.
if (!vrc->pLattice->pAltList[iStroke].alts[i].fCurrentPath)
{
for (l = i + 1; l < vrc->pLattice->pAltList[iStroke].nUsed; l++)
{
if (vrc->pLattice->pAltList[iStroke].alts[l].fCurrentPath &&
vrc->pLattice->pAltList[iStroke].alts[i].nStrokes ==
vrc->pLattice->pAltList[iStroke].alts[l].nStrokes)
{
bAllBreakSkip = TRUE;
break;
}
}
}
if (bAllBreakSkip) continue;
}
if (vrc->pLattice->pAltList[iStroke].alts[i].nStrokes > iStroke-iLastStroke)
{
dbElement.iColumn = iStroke;
dbElement.iIndex = i;
dbElement.pNext = NULL;
dbList.bCurrentPath = vrc->pLattice->pAltList[iStroke].alts[i].fCurrentPath;
// We found one that contains uiLastStroke
if (!GetRecDifSegAltList(iStroke, i, &dbList, &altStruct))
{
hr = E_OUTOFMEMORY;
}
}
}
}
iStroke--;
}
// If something went wrong, then clean up before returning
if (!SUCCEEDED(hr))
{
AltRank *pCur = pAltRankList->pFirst;
while (pCur != NULL)
{
AltRank *pNext = pCur->next;
DestroyAlternateInternal(pCur->wispalt);
ExternFree(pCur);
pCur = pNext;
}
pAltRankList->pFirst = pAltRankList->pLast = NULL;
pAltRankList->ulSize = 0;
}
return hr;
}
HRESULT FitAlternateToRecoRange(VRC *vrc, struct WispAlternate *wispalt, RECO_RANGE recoRange)
{
HRESULT hr = S_OK;
int *newColumns = NULL;
int *newIndexes = NULL;
int iCurrent = 0, j = 0;
UINT i = 0;
int iNumberOfColumns = 0;
// Return straight away if the reco range is already good
if (recoRange.iwcBegin == wispalt->OriginalRecoRange.iwcBegin &&
recoRange.cCount == wispalt->OriginalRecoRange.cCount)
return S_OK;
// Allocate the new arrays
iNumberOfColumns = wispalt->iNumberOfColumns + recoRange.cCount - wispalt->OriginalRecoRange.cCount;
newColumns = (int*)ExternAlloc(sizeof(int)*iNumberOfColumns);
if (!newColumns)
return E_OUTOFMEMORY;
newIndexes = (int*)ExternAlloc(sizeof(int)*iNumberOfColumns);
if (!newIndexes)
{
ExternFree(newColumns);
return E_OUTOFMEMORY;
}
iCurrent = 0;
// Copy the first elements of the array
for (i = recoRange.iwcBegin; i < wispalt->OriginalRecoRange.iwcBegin; i++)
{
// Fill with the information from the best result
newColumns[iCurrent] = vrc->pLatticePath->pElem[i].iStroke;
newIndexes[iCurrent] = vrc->pLatticePath->pElem[i].iAlt;
iCurrent++;
}
// Copy the existing alternate information
for (j = 0; j < wispalt->iNumberOfColumns; j++)
{
newColumns[iCurrent] = wispalt->pColumnIndex[j];
newIndexes[iCurrent] = wispalt->pIndexInColumn[j];
iCurrent++;
}
// Copy what follows with the information from the best result
for (i = wispalt->OriginalRecoRange.iwcBegin + wispalt->OriginalRecoRange.cCount;
i < recoRange.iwcBegin + recoRange.cCount; i++)
{
newColumns[iCurrent] = vrc->pLatticePath->pElem[i].iStroke;
newIndexes[iCurrent] = vrc->pLatticePath->pElem[i].iAlt;
iCurrent++;
}
ASSERT (iCurrent == iNumberOfColumns);
// Swap the arrays
ExternFree(wispalt->pColumnIndex);
ExternFree(wispalt->pIndexInColumn);
wispalt->pColumnIndex = newColumns;
wispalt->pIndexInColumn = newIndexes;
wispalt->iLength = iCurrent;
wispalt->iNumberOfColumns = iCurrent;
return hr;
}
// GetAlternateList
//
// This function returns alternates of the best result
//
// Parameters:
// hrc [in] : The handle to the reco context
// pRecoRange [in, out] : Pointer to a RECO_RANGE that contains the range we want to get
// the alternates for. This range comes bck modified to
// reflect the range we actually used.
// pSize [in, out] : The number of alternates. If phrcalt is NULL then this function returns
// the number of alternates it can return - Note we may return an arbitrary
// number with an HRESULT S_FALSE if we think that the number of alternate
// is too long to compute.
// phrcalt [out] : Array of alternates used to return the alternate list
// iBreak [in] : Mode for querying alternates: ALT_BREAKS_SAME, ALT_BREAKS_FULL or ALT_BREAKS_UNIQUE
/////////////////
HRESULT WINAPI GetAlternateList(HRECOCONTEXT hrc, RECO_RANGE* pRecoRange, ULONG*pSize, HRECOALT *phrcalt, ALT_BREAKS iBreak)
{
HRESULT hr = S_OK;
struct WispContext *wisphrc;
VRC *vrc = NULL;
RECO_RANGE recoRange, widestRecoRange;
ULONG i = 0;
ULONG iAlt;
int j = 0;
int iColumnIndex = 0;
FLOAT fCurrentScore = 0.0;
BOOL bSomethingAdded = FALSE;
AltRank *pCur = NULL, *pTemp1 = NULL, *pTemp2 = NULL;
ULONG ulAltCountSameStrokeCount = 0;
AltRankList altRankList;
int iFirstStroke = 0;
int iLastStroke = 0;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (pRecoRange != NULL && IsBadReadPtr(pRecoRange, sizeof(RECO_RANGE)))
{
return E_POINTER;
}
if (IsBadWritePtr(pSize, sizeof(ULONG)))
{
return E_POINTER;
}
if (phrcalt && IsBadWritePtr(phrcalt, (*pSize) * sizeof(*phrcalt)))
{
return E_POINTER;
}
if (iBreak != ALT_BREAKS_FULL &&
// iBreak != LARGE_BREAKS &&
iBreak != ALT_BREAKS_UNIQUE &&
iBreak != ALT_BREAKS_SAME)
{
return E_INVALIDARG;
}
vrc = (VRC*)wisphrc->hrc;
if (!vrc || !vrc->pLatticePath)
{
// There is no ink
*pSize = 0;
return TPC_E_NOT_RELEVANT;
}
// Check the reco range to see if it is valid
if (pRecoRange)
{
recoRange = *pRecoRange;
if (!recoRange.cCount) return E_INVALIDARG;
if (recoRange.iwcBegin + recoRange.cCount > (ULONG)vrc->pLatticePath->nChars)
return E_INVALIDARG;
}
else
{
recoRange.iwcBegin = 0;
recoRange.cCount = vrc->pLatticePath->nChars;
}
// First trim spaces (if any) from the beginning and end of the reco range
while (recoRange.cCount > 0 && vrc->pLatticePath->pElem[recoRange.iwcBegin].iAlt == SPACE_ALT_ID)
{
recoRange.iwcBegin++;
recoRange.cCount--;
}
while (recoRange.cCount > 0 && vrc->pLatticePath->pElem[recoRange.iwcBegin + recoRange.cCount - 1].iAlt == SPACE_ALT_ID)
{
recoRange.cCount--;
}
// If the range only contained spaces, then return an error
if (recoRange.cCount == 0)
{
return TPC_E_NOT_RELEVANT;
}
// If there aren't any results, error
if (!vrc->pLatticePath->nChars)
{
*pSize = 0;
return TPC_E_NOT_RELEVANT;
}
// If we are passed a buffer for alternates but it has size zero, just
// return immediately. (Some of the code for handling alternates doesn't
// work with a buffer size of zero.)
if (phrcalt != NULL && *pSize == 0)
{
return S_OK;
}
// If we're in single segmentation mode and have asked for full breaks, then
// switch to same breaks.
if ((wisphrc->dwFlags & RECOFLAG_SINGLESEG) != 0 && iBreak == ALT_BREAKS_FULL)
{
iBreak = ALT_BREAKS_SAME;
}
widestRecoRange = recoRange;
if (iBreak == ALT_BREAKS_FULL || iBreak == LARGE_BREAKS)
{
// Get the number of alternates
if (!phrcalt)
{
*pSize = 50; //We need to find a way how to calculate the real count easily...
return S_FALSE;
}
iLastStroke = vrc->pLatticePath->pElem[recoRange.iwcBegin+recoRange.cCount-1].iStroke;
iFirstStroke = vrc->pLatticePath->pElem[recoRange.iwcBegin].iStroke -
vrc->pLatticePath->pElem[recoRange.iwcBegin].nStrokes + 1;
hr = GetDifSegAltList(vrc, iLastStroke, iFirstStroke, *pSize, &altRankList, iBreak, recoRange.iwcBegin, recoRange.iwcBegin+recoRange.cCount-1);
if (FAILED(hr))
{
return hr;
}
// Copy the info from the list to the array
*pSize = altRankList.ulSize;
if (altRankList.ulSize == 0) return S_OK;
// TBD: Adjust the alternates to fit the "widest" returned
// alternate
// First find the widest alternate (widestRecoRange)
if (iBreak == LARGE_BREAKS)
{
pCur = altRankList.pFirst;
widestRecoRange = pCur->wispalt->OriginalRecoRange;
for (i = 0; i < *pSize; i++)
{
// Check the start point
if (widestRecoRange.iwcBegin > pCur->wispalt->OriginalRecoRange.iwcBegin)
{
widestRecoRange.cCount += widestRecoRange.iwcBegin -
pCur->wispalt->OriginalRecoRange.iwcBegin;
widestRecoRange.iwcBegin = pCur->wispalt->OriginalRecoRange.iwcBegin;
}
// Check the end point
if (widestRecoRange.iwcBegin + widestRecoRange.cCount <
pCur->wispalt->OriginalRecoRange.iwcBegin +
pCur->wispalt->OriginalRecoRange.cCount)
{
widestRecoRange.cCount = pCur->wispalt->OriginalRecoRange.iwcBegin
+ pCur->wispalt->OriginalRecoRange.cCount
- widestRecoRange.iwcBegin;
}
// Go to the next
pCur = pCur->next;
}
pCur = altRankList.pFirst;
// Then call on each alternate the "fit" function
for (i = 0; i < *pSize; i++)
{
hr = FitAlternateToRecoRange(vrc, pCur->wispalt, widestRecoRange);
// Go to the next
pCur = pCur->next;
}
}
pCur = altRankList.pFirst;
pTemp1 = altRankList.pFirst;
}
if (iBreak == ALT_BREAKS_UNIQUE || iBreak == ALT_BREAKS_SAME)
{
if (iBreak == ALT_BREAKS_UNIQUE && !phrcalt)
{
// Get the number of alternates
*pSize = 50; //We need to find a way how to calculate the real count easily... Impossible?
// If we're pretending there is only one segmentation...
if (wisphrc->dwFlags & RECOFLAG_SINGLESEG)
{
*pSize = 1;
}
return S_FALSE;
}
if (!vrc->pLatticePath)
{
*pSize = 0;
return hr;
}
// Get the number of alternates
if (!phrcalt)
{
*pSize = 1;
for (i = recoRange.iwcBegin; i < recoRange.iwcBegin + recoRange.cCount; i++)
{
iColumnIndex = vrc->pLatticePath->pElem[i].iStroke;
// We need to get the number of alternates with the same number of strokes!!!
ulAltCountSameStrokeCount = 0;
for (j = 0; j < vrc->pLattice->pAltList[iColumnIndex].nUsed; j++)
{
if (vrc->pLattice->pAltList[iColumnIndex].alts[j].nStrokes ==
vrc->pLatticePath->pElem[i].nStrokes)
ulAltCountSameStrokeCount++;
}
*pSize *= ulAltCountSameStrokeCount;
}
return S_OK;
}
// If we're in single segmentation mode and have asked for unique breaks, then
// we just want to return the best path. Easiest way to do this is to
// ask for same breaks with one alternate.
if ((wisphrc->dwFlags & RECOFLAG_SINGLESEG) != 0 && iBreak == ALT_BREAKS_UNIQUE)
{
if (*pSize > 1)
{
*pSize = 1;
}
iBreak = ALT_BREAKS_SAME;
}
// Get the alternates
// Create a list of alternates
iLastStroke = vrc->pLatticePath->pElem[recoRange.iwcBegin+recoRange.cCount-1].iStroke;
iFirstStroke = vrc->pLatticePath->pElem[recoRange.iwcBegin].iStroke -
vrc->pLatticePath->pElem[recoRange.iwcBegin].nStrokes + 1;
hr = GetDifSegAltList(vrc, iLastStroke, iFirstStroke, *pSize, &altRankList, iBreak, recoRange.iwcBegin, recoRange.iwcBegin+recoRange.cCount-1);
if (FAILED(hr))
{
return hr;
}
// Copy the info from the list to the array
*pSize = altRankList.ulSize;
pCur = altRankList.pFirst;
pTemp1 = altRankList.pFirst;
if (altRankList.ulSize == 0) return S_OK;
}
for (i = 0; i < *pSize; i++)
{
// Allocate the memory for the pRecoRange array
pCur->wispalt->OriginalRecoRange = recoRange;
pCur->wispalt->hrc = hrc;
// create a tpg handle
phrcalt[i] = (HRECOALT)CreateTpgHandle(TPG_HRECOALT, pCur->wispalt);
// if we fail we'll have to destroy all the other handles
if (phrcalt[i] == NULL)
{
for (iAlt = 0; iAlt < i; iAlt++)
{
DestroyTpgHandle(phrcalt[iAlt], TPG_HRECOALT);
}
// And also destroy the alternate list
while (pTemp1)
{
pTemp2 = pTemp1->next;
DestroyAlternateInternal(pTemp1->wispalt);
ExternFree(pTemp1);
pTemp1 = pTemp2;
}
return E_OUTOFMEMORY;
}
// Go to the next
pCur = pCur->next;
}
// Get rid of the linked list which previous held all the alternates
while (pTemp1)
{
pTemp2 = pTemp1->next;
ExternFree(pTemp1);
pTemp1 = pTemp2;
}
if (pRecoRange)
*pRecoRange = widestRecoRange;
return hr;
}
HRESULT WINAPI Process(HRECOCONTEXT hrc, BOOL *pbPartialProcessing)
{
struct WispContext *wisphrc;
HRESULT hr = S_OK;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pbPartialProcessing, sizeof(BOOL)))
return E_POINTER;
*pbPartialProcessing = FALSE;
if (!wisphrc->hrc)
{
return S_OK; // There is no ink
}
// We should call the HwxProcess if there is a Guide
if (wisphrc->bIsBoxed)
{
if (wisphrc->bIsCAC)
{
hr = EndInkInput(hrc);
if (FAILED(hr)) return hr;
wisphrc->bCACEndInk = TRUE;
}
if (HwxProcess(wisphrc->hrc))
{
// Test wether the result is valid or invalid
// the result can be invalid if the call to Process was
// interrupted by a call to AdviseInkChanged
if (wisphrc->uAbort != (ULONG)((VRC*)wisphrc->hrc)->pLattice->nRealStrokes)
return TPC_S_INTERRUPTED;
return hr;
}
}
else
{
if (HRCR_OK == ProcessHRC(wisphrc->hrc, 0))
return S_OK;
}
return E_FAIL;
}
HRESULT WINAPI SetFactoid(HRECOCONTEXT hrc, ULONG cwcFactoid, const WCHAR* pwcFactoid)
{
struct WispContext *wisphrc;
HRESULT hr = S_OK;
WCHAR *wszOldFactoid;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
// Save the old factoid so it can be restored if there is an error
wszOldFactoid = wisphrc->wszFactoid;
if (pwcFactoid)
{
// validate pointer if not null
if (IsBadReadPtr (pwcFactoid, cwcFactoid * sizeof (*pwcFactoid)))
{
return E_POINTER;
}
wisphrc->wszFactoid = (WCHAR*)ExternAlloc(sizeof(WCHAR)*(cwcFactoid+1));
if (!wisphrc->wszFactoid)
{
wisphrc->wszFactoid = wszOldFactoid;
return E_OUTOFMEMORY;
}
memcpy(wisphrc->wszFactoid, pwcFactoid, cwcFactoid * sizeof(WCHAR));
wisphrc->wszFactoid[cwcFactoid] = 0;
}
else
{
wisphrc->wszFactoid = NULL;
}
// If we have an HRC already, set the factoid in it.
if (wisphrc->hrc != NULL)
{
switch (SetHwxFactoid(wisphrc->hrc, wisphrc->wszFactoid))
{
case HRCR_OK:
hr = S_OK;
break;
case HRCR_UNSUPPORTED:
hr = TPC_E_INVALID_PROPERTY;
break;
case HRCR_CONFLICT:
hr = TPC_E_OUT_OF_ORDER_CALL;
break;
case HRCR_ERROR:
default:
hr = E_FAIL;
break;
}
}
else
{
// Try to create an HRC to test out the factoid setting,
// then destroy it immediately.
hr = CreateHRCinContext(wisphrc);
// Destroy the HRC if we succeeded in creating one.
if (wisphrc->hrc != NULL)
{
if (wisphrc->bIsBoxed)
HwxDestroy(wisphrc->hrc);
else
DestroyHRC(wisphrc->hrc);
wisphrc->hrc = NULL;
}
}
if (SUCCEEDED(hr))
{
ExternFree(wszOldFactoid);
}
else
{
ExternFree(wisphrc->wszFactoid);
wisphrc->wszFactoid = wszOldFactoid;
}
return hr;
}
HRESULT WINAPI SetFlags(HRECOCONTEXT hrc, DWORD dwFlags)
{
struct WispContext *wisphrc;
DWORD dwOldFlags;
HRESULT hr;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
dwOldFlags = wisphrc->dwFlags;
wisphrc->dwFlags = dwFlags;
if (wisphrc->hrc)
{
if (SetHwxFlags(wisphrc->hrc, dwFlags))
hr = S_OK;
else
hr = E_INVALIDARG;
}
else
{
// Try to create an HRC to set out the flag setting,
// then destroy it immediately.
hr = CreateHRCinContext(wisphrc);
// Destroy the HRC if we succeeded in creating one.
if (wisphrc->hrc != NULL)
{
if (wisphrc->bIsBoxed)
HwxDestroy(wisphrc->hrc);
else
DestroyHRC(wisphrc->hrc);
wisphrc->hrc = NULL;
}
}
if (FAILED(hr))
{
wisphrc->dwFlags = dwOldFlags;
}
return hr;
}
HRESULT WINAPI IsStringSupported(HRECOCONTEXT hrc, ULONG cwcString, const WCHAR *pwcString)
{
struct WispContext *wisphrc;
WCHAR *tempBuffer;
ULONG ulSize = 0;
HRESULT hr = S_OK;
BOOL fCreatedHRC = FALSE;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
if (IsBadReadPtr(pwcString, cwcString * sizeof(*pwcString)))
{
return E_POINTER;
}
// We need to have a valid HRC to check the factoid
if (!wisphrc->hrc)
{
hr = CreateHRCinContext(wisphrc);
if (FAILED(hr))
{
// Failure might mean we actually made the
// HRC, but a flag setting or factoid setting failed.
// So destroy the HRC if it was created.
if (wisphrc->hrc != NULL)
{
if (wisphrc->bIsBoxed)
HwxDestroy(wisphrc->hrc);
else
DestroyHRC(wisphrc->hrc);
wisphrc->hrc = NULL;
}
return E_FAIL;
}
fCreatedHRC = TRUE;
}
tempBuffer = (WCHAR *) ExternAlloc((cwcString + 1) * sizeof(*tempBuffer));
if (!tempBuffer)
return E_OUTOFMEMORY;
memcpy(tempBuffer, pwcString, cwcString * sizeof(WCHAR));
tempBuffer[cwcString] = 0;
if (IsWStringSupportedHRC(wisphrc->hrc, tempBuffer))
hr = S_OK;
else
hr = S_FALSE;
ExternFree(tempBuffer);
if (fCreatedHRC)
{
if (wisphrc->bIsBoxed)
HwxDestroy(wisphrc->hrc);
else
DestroyHRC(wisphrc->hrc);
wisphrc->hrc = NULL;
}
return hr;
}
int _cdecl CompareWCHAR(const void *arg1, const void *arg2)
{
int wch1 = *((WCHAR *) arg1);
int wch2 = *((WCHAR *) arg2);
return (wch1 - wch2);
}
// GetUnicodeRanges
//
// Parameters:
// hrec [in] : Handle to the recognizer
// pcRanges [in/out] : Count of ranges
// pcr [out] : Array of character ranges
////////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI GetUnicodeRanges(HRECOGNIZER hrec,
ULONG *pcRanges,
CHARACTER_RANGE *pcr)
{
struct WispRec *pRec;
WCHAR *aw;
int cChar, i;
ULONG cRange, iRange = 0;
HRESULT hr = S_OK;
// Check the recognizer handle
pRec = (struct WispRec*)FindTpgHandle((HANDLE)hrec, TPG_HRECOGNIZER);
if (NULL == pRec)
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pcRanges, sizeof(ULONG)))
{
return E_POINTER;
}
if (pcr != NULL && IsBadWritePtr(pcr, sizeof(CHARACTER_RANGE) * (*pcRanges)))
{
return E_POINTER;
}
cChar = g_locRunInfo.cCodePoints - 1;
aw = (WCHAR *) ExternAlloc(cChar * sizeof(WCHAR));
if (!aw)
{
return E_OUTOFMEMORY;
}
for (i = 1; i < g_locRunInfo.cCodePoints; i++)
{
aw[i - 1] = LocRunDense2Unicode(&g_locRunInfo, (WCHAR) i);
}
if (cChar == 0)
{
cRange = 0;
}
else
{
qsort((void*)aw, (size_t)cChar, sizeof(WCHAR), CompareWCHAR);
// count the ranges
cRange = 1;
for (i = 1; i < cChar; i++)
{
if (aw[i] > aw[i - 1] + 1)
cRange++;
}
}
if (!pcr) // Need only a count of ranges
{
*pcRanges = cRange;
goto cleanup;
}
if (*pcRanges < cRange)
{
hr = TPC_E_INSUFFICIENT_BUFFER;
goto cleanup;
}
if (*pcRanges > cRange)
{
*pcRanges = cRange;
}
if (*pcRanges > 0)
{
// convert the array of Unicode values to an array of CHARACTER_RANGEs
pcr[iRange].wcLow = aw[0];
pcr[iRange].cChars = 1;
for (i = 1; i < cChar; i++)
{
if (aw[i] == aw[i - 1] + 1)
pcr[iRange].cChars++;
else
{
if (iRange >= (*pcRanges) - 1)
{
break;
}
iRange++;
pcr[iRange].wcLow = aw[i];
pcr[iRange].cChars = 1;
}
}
ASSERT(iRange == (*pcRanges) - 1);
}
cleanup:
ExternFree(aw);
return hr;
}
// GetEnabledUnicodeRanges
//
// Parameters:
// hrc [in] : Handle to the recognition context
// pcRanges [in/out] : Count of ranges
// pcr [out] : Array of character ranges
////////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI GetEnabledUnicodeRanges(HRECOCONTEXT hrc,
ULONG *pcRanges,
CHARACTER_RANGE *pcr)
{
VRC *pVRC;
CHARSET charset;
WCHAR *aw;
int cChar, i;
ULONG cRange, iRange = 0;
HRESULT hr = S_OK;
BOOL fCreatedHRC = FALSE;
struct WispContext *wisphrc;
// validate the correpsonding hrc pointer
wisphrc = (struct WispContext *) FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pcRanges, sizeof(ULONG)))
{
return E_POINTER;
}
if (pcr != NULL && IsBadWritePtr(pcr, sizeof(CHARACTER_RANGE) * *(pcRanges)))
{
return E_POINTER;
}
cChar = 0;
aw = (WCHAR *) ExternAlloc((g_locRunInfo.cCodePoints - 1) * sizeof(WCHAR));
if (!aw)
return E_OUTOFMEMORY;
// If we have an HRC, the factoid should be set already. If not, we'll have
// to make one.
if (wisphrc->hrc == NULL)
{
fCreatedHRC = TRUE;
hr = CreateHRCinContext(wisphrc);
}
pVRC = (VRC *) wisphrc->hrc;
if (SUCCEEDED(hr) && pVRC != NULL)
{
charset.recmask = pVRC->pLattice->alcFactoid;
charset.pbAllowedChars = pVRC->pLattice->pbFactoidChars;
for (i = 1; i < g_locRunInfo.cCodePoints; i++)
{
if (IsAllowedChar(&g_locRunInfo, &charset, (WCHAR) i))
{
aw[cChar++] = LocRunDense2Unicode(&g_locRunInfo, (WCHAR) i);
}
}
}
if (fCreatedHRC)
{
// Destroy the HRC if we created one.
if (wisphrc->hrc != NULL)
{
if (wisphrc->bIsBoxed)
HwxDestroy(wisphrc->hrc);
else
DestroyHRC(wisphrc->hrc);
wisphrc->hrc = NULL;
}
}
if (cChar == 0)
{
cRange = 0;
}
else
{
qsort((void*)aw, (size_t)cChar, sizeof(WCHAR), CompareWCHAR);
// count the ranges
cRange = 1;
for (i = 1; i < cChar; i++)
{
if (aw[i] > aw[i - 1] + 1)
cRange++;
}
}
if (!pcr) // Need only a count of ranges
{
*pcRanges = cRange;
goto cleanup;
}
if (*pcRanges < cRange)
{
hr = TPC_E_INSUFFICIENT_BUFFER;
goto cleanup;
}
if (*pcRanges > cRange)
{
*pcRanges = cRange;
}
if (*pcRanges > 0)
{
// convert the array of Unicode values to an array of CHARACTER_RANGEs
pcr[iRange].wcLow = aw[0];
pcr[iRange].cChars = 1;
for (i = 1; i < cChar; i++)
{
if (aw[i] == aw[i - 1] + 1)
pcr[iRange].cChars++;
else
{
if (iRange >= (*pcRanges) - 1)
{
break;
}
iRange++;
pcr[iRange].wcLow = aw[i];
pcr[iRange].cChars = 1;
}
}
ASSERT(iRange == (*pcRanges) - 1);
}
cleanup:
ExternFree(aw);
return hr;
}
// SetEnabledUnicodeRanges
//
// Parameters:
// hrc [in] : Handle to the recognition context
// pcRanges [in/out] : Count of ranges
// pcr [out] : Array of character ranges
////////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI SetEnabledUnicodeRanges(HRECOCONTEXT hrc,
ULONG cRanges,
CHARACTER_RANGE *pcr)
{
struct WispContext *wisphrc;
// validate the correpsonding hrc pointer
wisphrc = (struct WispContext *) FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_INVALIDARG;
}
if (IsBadReadPtr(pcr, sizeof(CHARACTER_RANGE) * cRanges))
{
return E_POINTER;
}
return E_NOTIMPL;
}
////////////////////////
// IAlternate
////////////////////////
HRESULT WINAPI GetString(HRECOALT hrcalt, RECO_RANGE *pRecoRange, ULONG* pcSize, WCHAR* szString)
{
struct WispContext *wisphrc;
struct WispAlternate *wispalt;
VRC *vrc = NULL;
HRESULT hr = S_OK;
ULONG i = 0, ulSize = 0;
// find the handle and validate the correpsonding pointer
wispalt = (struct WispAlternate*)FindTpgHandle((HANDLE)hrcalt, TPG_HRECOALT);
if (NULL == wispalt)
{
return E_INVALIDARG;
}
// validate the correpsonding hrc pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)wispalt->hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_INVALIDARG;
}
if (pRecoRange && IsBadWritePtr(pRecoRange, sizeof(RECO_RANGE)))
{
return E_POINTER;
}
if (IsBadWritePtr(pcSize, sizeof(ULONG)))
{
return E_POINTER;
}
// if the string pointer is not null, validate it
if (szString && IsBadWritePtr(szString, (*pcSize) * sizeof (*szString)))
{
return E_POINTER;
}
vrc = (VRC*)wisphrc->hrc;
if (!vrc)
{
return E_POINTER;
}
if (pRecoRange)
{
pRecoRange->iwcBegin = wispalt->OriginalRecoRange.iwcBegin;
pRecoRange->cCount = wispalt->OriginalRecoRange.cCount;
}
ulSize = (ULONG)wispalt->iLength;
if (!szString)
{
*pcSize = ulSize;
return S_OK;
}
if (*pcSize > ulSize)
{
*pcSize = ulSize;
}
if (*pcSize < ulSize)
{
hr = TPC_S_TRUNCATED;
}
// Fill the string
for (i = 0; i<*pcSize; i++)
{
// Fill the characters in the string
if (wispalt->pIndexInColumn[i] == SPACE_ALT_ID)
{
szString[i] = SYM_SPACE;
}
else
if (vrc->pLattice->pAltList[wispalt->pColumnIndex[i]].alts[wispalt->pIndexInColumn[i]].wChar != SYM_UNKNOWN)
{
szString[i] = LocRunDense2Unicode(&g_locRunInfo,
vrc->pLattice->pAltList[wispalt->pColumnIndex[i]].alts[wispalt->pIndexInColumn[i]].wChar);
}
else
{
szString[i] = SYM_UNKNOWN;
}
}
return hr;
}
HRESULT WINAPI GetStrokeRanges(HRECOALT hrcalt, RECO_RANGE* pRecoRange, ULONG* pcRanges, STROKE_RANGE* pStrokeRange)
{
HRESULT hr = S_OK;
RECO_RANGE recoRange;
struct WispContext *wisphrc;
struct WispAlternate *wispalt;
VRC *vrc;
ULONG ulStrokeCount = 0, ulCurrentIndex = 0;
ULONG i = 0;
int j = 0;
int k = 0;
ULONG *StrokeArray = NULL;
ULONG ulStrokeRangesCount = 0;
ULONG iCurrentStrokeRange = 0;
// find the handle and validate the corresponding pointer
wispalt = (struct WispAlternate*)FindTpgHandle((HANDLE)hrcalt, TPG_HRECOALT);
if (NULL == wispalt)
{
return E_INVALIDARG;
}
// validate the corresponding hrc pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)wispalt->hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_INVALIDARG;
}
vrc = (VRC *) wisphrc->hrc;
if (vrc == NULL)
{
return E_INVALIDARG;
}
if (IsBadReadPtr(pRecoRange, sizeof(RECO_RANGE)))
{
return E_POINTER;
}
if (IsBadWritePtr(pcRanges, sizeof(ULONG)))
{
return E_POINTER;
}
// validate pointer if not null
if (pStrokeRange && IsBadWritePtr(pStrokeRange, (*pcRanges) * sizeof (*pStrokeRange)))
{
return E_POINTER;
}
recoRange = *pRecoRange;
if (!recoRange.cCount)
{
*pcRanges = 0;
return S_OK;
}
if (recoRange.iwcBegin + recoRange.cCount > (ULONG)wispalt->iLength)
return E_INVALIDARG;
// Get the number of strokes
for (i = recoRange.iwcBegin; i < recoRange.iwcBegin + recoRange.cCount; i++)
{
// Make sure we're not looking at a space
if (wispalt->pIndexInColumn[i] != SPACE_ALT_ID)
{
// There might be some stroke that have been merged!
// We need to examine every single column to know if strokes have been merged
// (and also how many times)
for (j = 0; j < vrc->pLattice->pAltList[wispalt->pColumnIndex[i]].alts[wispalt->pIndexInColumn[i]].nStrokes; j++)
{
ulStrokeCount += vrc->pLattice->pStroke[wispalt->pColumnIndex[i]-j].iLast -
vrc->pLattice->pStroke[wispalt->pColumnIndex[i]-j].iOrder + 1;
}
}
}
// If there aren't any strokes, then exit early.
// (The rest of this function behaves badly if there are no strokes or no ranges.)
if (ulStrokeCount == 0)
{
*pcRanges = 0;
return S_OK;
}
// Allocate the array of strokes
StrokeArray = (ULONG*)ExternAlloc(sizeof(ULONG)*ulStrokeCount);
if (!StrokeArray)
{
ASSERT(StrokeArray);
return E_OUTOFMEMORY;
}
// Get the array of strokes
ulCurrentIndex = 0;
for (i = recoRange.iwcBegin; i < recoRange.iwcBegin + recoRange.cCount; i++)
{
// Make sure we're not looking at a space
if (wispalt->pIndexInColumn[i] != SPACE_ALT_ID)
{
// This loop goes backwards so we get the strokes in order
for (j = vrc->pLattice->pAltList[wispalt->pColumnIndex[i]].alts[wispalt->pIndexInColumn[i]].nStrokes - 1; j >= 0; j--)
{
// There might more than one stroke here
// because of the possibility of a stroke merge!!!
for (k = vrc->pLattice->pStroke[wispalt->pColumnIndex[i]-j].iOrder;
k <= vrc->pLattice->pStroke[wispalt->pColumnIndex[i]-j].iLast;
k++)
{
StrokeArray[ulCurrentIndex] = k;
ulCurrentIndex++;
}
}
}
}
// Sort the array
SlowSort(StrokeArray, ulStrokeCount);
// Get the number of STROKE_RANGES needed
ulStrokeRangesCount = 1;
for (i = 1; i<ulStrokeCount; i++)
{
if (StrokeArray[i-1]+1!=StrokeArray[i]) ulStrokeRangesCount++;
}
// Return the count is this is all that is asked
if (!pStrokeRange)
{
*pcRanges = ulStrokeRangesCount;
ExternFree(StrokeArray);
return S_OK;
}
if (*pcRanges < ulStrokeRangesCount)
{
ExternFree(StrokeArray);
return TPC_E_INSUFFICIENT_BUFFER;
}
// Fill in the Strokes
iCurrentStrokeRange = 0;
pStrokeRange[iCurrentStrokeRange].iStrokeBegin = StrokeArray[0];
pStrokeRange[ulStrokeRangesCount-1].iStrokeEnd = StrokeArray[ulStrokeCount-1];
for(i = 1; i < ulStrokeCount; i++)
{
if (StrokeArray[i-1]+1!=StrokeArray[i])
{
pStrokeRange[iCurrentStrokeRange].iStrokeEnd = StrokeArray[i-1];
iCurrentStrokeRange++;
if (iCurrentStrokeRange == ulStrokeRangesCount) break;
pStrokeRange[iCurrentStrokeRange].iStrokeBegin = StrokeArray[i];
}
}
*pcRanges = ulStrokeRangesCount;
ExternFree(StrokeArray);
return hr;
}
typedef struct AltScore
{
float flScore;
int iAlt;
BOOL fCurrentPath;
} AltScore;
int __cdecl CompareAltScore(const void *p1, const void *p2)
{
const AltScore *pAlt1 = (const AltScore *) p1;
const AltScore *pAlt2 = (const AltScore *) p2;
if (pAlt1->fCurrentPath) return -1;
if (pAlt2->fCurrentPath) return 1;
if (pAlt1->flScore > pAlt2->flScore) return -1;
if (pAlt1->flScore < pAlt2->flScore) return 1;
return 0;
}
HRESULT WINAPI GetSegmentAlternateList(HRECOALT hrcalt, RECO_RANGE* pRecoRange, ULONG *pcAlts, HRECOALT* pAlts)
{
HRESULT hr = S_OK;
struct WispAlternate *wispalt;
struct WispContext *wisphrc;
VRC *vrc;
ULONG ulMaxAlt = 0;
struct WispAlternate *pWispAlt = NULL;
int i = 0;
int j = 0;
ULONG ulCurrentIndex = 0;
// find the handle and validate the correpsonding pointer
wispalt = (struct WispAlternate*)FindTpgHandle((HANDLE)hrcalt, TPG_HRECOALT);
if (NULL == wispalt)
{
return E_INVALIDARG;
}
// validate the corresponding hrc pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)wispalt->hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_INVALIDARG;
}
vrc = (VRC *) wisphrc->hrc;
if (vrc == NULL)
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pRecoRange, sizeof(RECO_RANGE)))
{
return E_POINTER;
}
if (IsBadWritePtr(pcAlts, sizeof(ULONG)))
{
return E_POINTER;
}
if (pAlts && IsBadWritePtr(pAlts, (*pcAlts) * sizeof (*pAlts)))
{
return E_POINTER;
}
// Check that the pRecoRange is valid:
if (pRecoRange->cCount == 0 ||
pRecoRange->iwcBegin + pRecoRange->cCount > (ULONG)wispalt->iLength)
{
return E_INVALIDARG;
}
// Get the number of alternates for this character (with the same number of strokes!!!)
ulMaxAlt = 0;
// if this char is a space
if (wispalt->pIndexInColumn[pRecoRange->iwcBegin] == SPACE_ALT_ID)
{
if (!pAlts)
{
*pcAlts = 1;
}
if (pAlts && *pcAlts > 0)
{
pWispAlt = (struct WispAlternate *)ExternAlloc(sizeof(struct WispAlternate));
if (!pWispAlt)
{
return E_OUTOFMEMORY;
}
pWispAlt->hrc = wispalt->hrc;
pWispAlt->iLength = 1;
pWispAlt->iNumberOfColumns = 1;
pWispAlt->OriginalRecoRange = *pRecoRange;
pWispAlt->pColumnIndex = NULL;
pWispAlt->pIndexInColumn = NULL;
pWispAlt->pColumnIndex = ExternAlloc(sizeof(int));
pWispAlt->pIndexInColumn = ExternAlloc(sizeof(int));
if (!pWispAlt->pColumnIndex || !pWispAlt->pIndexInColumn)
{
// Problem allocating memory, unallocate the array
HRESULT hrDA = DestroyAlternateInternal(pWispAlt);
ASSERT(SUCCEEDED(hrDA));
return E_OUTOFMEMORY;
}
pWispAlt->pColumnIndex[0] = wispalt->pColumnIndex[pRecoRange->iwcBegin];
pWispAlt->pIndexInColumn[0] = SPACE_ALT_ID;
pAlts[0] = (HRECOALT) CreateTpgHandle(TPG_HRECOALT, pWispAlt);
if (pAlts[0] == NULL)
{
// Problem allocating memory, unallocate the array
HRESULT hrDA = DestroyAlternateInternal(pWispAlt);
ASSERT(SUCCEEDED(hrDA));
return E_OUTOFMEMORY;
}
*pcAlts = 1;
}
}
else
{
AltScore *pAltScores;
int iCurrentPath = -1;
for (i = 0; i < vrc->pLattice->pAltList[wispalt->pColumnIndex[pRecoRange->iwcBegin]].nUsed; i++)
{
if (vrc->pLattice->pAltList[wispalt->pColumnIndex[pRecoRange->iwcBegin]].alts[i].nStrokes ==
vrc->pLatticePath->pElem[pRecoRange->iwcBegin].nStrokes)
ulMaxAlt++;
}
if (!pAlts)
{
*pcAlts = ulMaxAlt;
return S_OK;
}
pAltScores = (AltScore *) ExternAlloc(sizeof(AltScore) * ulMaxAlt);
if (pAltScores == NULL)
{
return E_OUTOFMEMORY;
}
ulCurrentIndex = 0;
for (i = 0; i < vrc->pLattice->pAltList[wispalt->pColumnIndex[pRecoRange->iwcBegin]].nUsed; i++)
{
// Do the stuff only when we have the same number of strokes
if (vrc->pLattice->pAltList[wispalt->pColumnIndex[pRecoRange->iwcBegin]].alts[i].nStrokes ==
vrc->pLatticePath->pElem[pRecoRange->iwcBegin].nStrokes)
{
pAltScores[ulCurrentIndex].fCurrentPath = vrc->pLattice->pAltList[wispalt->pColumnIndex[pRecoRange->iwcBegin]].alts[i].fCurrentPath;
pAltScores[ulCurrentIndex].iAlt = i;
pAltScores[ulCurrentIndex].flScore =
vrc->pLattice->pAltList[wispalt->pColumnIndex[pRecoRange->iwcBegin]].alts[i].logProbPath;
// GetScore(vrc->pLattice, wispalt->pColumnIndex[pRecoRange->iwcBegin], i);
ulCurrentIndex++;
}
}
qsort(pAltScores, ulMaxAlt, sizeof(AltScore), CompareAltScore);
if (*pcAlts>ulMaxAlt) *pcAlts = ulMaxAlt;
// Fill in the array of alternates
for (i = 0; i < (int)(*pcAlts); i++)
{
// Create an alternate
pWispAlt = (struct WispAlternate *)ExternAlloc(sizeof(struct WispAlternate));
if (!pWispAlt)
{
// Problem allocating memory, unallocate the array
ExternFree(pAltScores);
for (j = 0; j < i; j++)
{
HRESULT hrDA = DestroyAlternate(pAlts[j]);
ASSERT(SUCCEEDED(hrDA));
}
return E_OUTOFMEMORY;
}
pWispAlt->hrc = wispalt->hrc;
pWispAlt->iLength = 1;
pWispAlt->iNumberOfColumns = 1;
pWispAlt->OriginalRecoRange = *pRecoRange;
pWispAlt->pColumnIndex = NULL;
pWispAlt->pIndexInColumn = NULL;
pWispAlt->pColumnIndex = ExternAlloc(sizeof(int));
pWispAlt->pIndexInColumn = ExternAlloc(sizeof(int));
if (!pWispAlt->pColumnIndex || !pWispAlt->pIndexInColumn)
{
// Problem allocating memory, unallocate the array
ExternFree(pAltScores);
for (j = 0; j < i; j++)
{
HRESULT hrDA = DestroyAlternate(pAlts[j]);
ASSERT(SUCCEEDED(hrDA));
}
return E_OUTOFMEMORY;
}
pWispAlt->pColumnIndex[0] = wispalt->pColumnIndex[pRecoRange->iwcBegin];
pWispAlt->pIndexInColumn[0] = pAltScores[i].iAlt;
pAlts[i] = CreateTpgHandle(TPG_HRECOALT, pWispAlt);
if (pAlts[i] == NULL)
{
// Problem allocating memory, unallocate the array
ExternFree(pAltScores);
for (j = 0; j < i; j++)
{
HRESULT hrDA = DestroyAlternate(pAlts[j]);
ASSERT(SUCCEEDED(hrDA));
}
return E_OUTOFMEMORY;
}
}
ExternFree(pAltScores);
}
pRecoRange->cCount = 1;
return hr;
}
HRESULT WINAPI GetMetrics(HRECOALT hrcalt, RECO_RANGE* pRecoRange, LINE_METRICS lm, LINE_SEGMENT* pls)
{
struct WispAlternate *wispalt;
struct WispContext *wisphrc;
VRC *vrc;
HRESULT hr = S_OK;
ULONG index = 0;
LONG lPrevChar = 0;
float flTotalY = 0;
int cCharacters = 0;
// find the handle and validate the correpsonding pointer
wispalt = (struct WispAlternate*)FindTpgHandle((HANDLE)hrcalt, TPG_HRECOALT);
if (NULL == wispalt)
{
return E_INVALIDARG;
}
// validate the corresponding hrc pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)wispalt->hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_INVALIDARG;
}
vrc = (VRC *) wisphrc->hrc;
if (vrc == NULL)
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pRecoRange, sizeof(RECO_RANGE)))
{
return E_POINTER;
}
if (IsBadWritePtr(pls, sizeof(LINE_SEGMENT)))
{
return E_POINTER;
}
if (pRecoRange->cCount == 0 ||
pRecoRange->iwcBegin+pRecoRange->cCount > (ULONG)wispalt->iLength)
{
return E_INVALIDARG;
}
// First trim spaces (if any) from the beginning and end of the reco range
while (pRecoRange->cCount > 0 && wispalt->pIndexInColumn[pRecoRange->iwcBegin] == SPACE_ALT_ID)
{
pRecoRange->iwcBegin++;
pRecoRange->cCount--;
}
while (pRecoRange->cCount > 0 && wispalt->pIndexInColumn[pRecoRange->iwcBegin + pRecoRange->cCount - 1] == SPACE_ALT_ID)
{
pRecoRange->cCount--;
}
// If the range only contained spaces, then return an error
if (pRecoRange->cCount == 0)
{
return TPC_E_NOT_RELEVANT;
}
index = 0;
lPrevChar = 0;
// Right now we only work from left to right, top to bottom so we will compare the x coordinates
// of two consecutive writing boxes to know if we have a new line
while (index < pRecoRange->cCount)
{
int iColumn = wispalt->pColumnIndex[pRecoRange->iwcBegin+index];
int iIndexInColumn = wispalt->pIndexInColumn[pRecoRange->iwcBegin+index];
// Skip over spaces in the range
if (iIndexInColumn == SPACE_ALT_ID)
{
index++;
continue;
}
// Check if we switched to a new line
if (index > 0 &&
lPrevChar > vrc->pLattice->pAltList[iColumn].alts[iIndexInColumn].writingBox.left)
{
// Looks like we moved to a new line, modify the reco range to end here and exit the loop.
pRecoRange->cCount = index;
// Back up over spaces until we reach the actual end of the previous line
while (pRecoRange->cCount > 0 && wispalt->pIndexInColumn[pRecoRange->iwcBegin + pRecoRange->cCount - 1] == SPACE_ALT_ID)
{
pRecoRange->cCount--;
}
break;
}
lPrevChar = vrc->pLattice->pAltList[iColumn].alts[iIndexInColumn].writingBox.left;
switch(lm)
{
case LM_BASELINE:
case LM_DESCENDER:
flTotalY += vrc->pLattice->pAltList[iColumn].alts[iIndexInColumn].writingBox.bottom;
break;
case LM_MIDLINE:
flTotalY += (vrc->pLattice->pAltList[iColumn].alts[iIndexInColumn].writingBox.bottom +
vrc->pLattice->pAltList[iColumn].alts[iIndexInColumn].writingBox.top) / 2;
break;
case LM_ASCENDER:
flTotalY += vrc->pLattice->pAltList[iColumn].alts[iIndexInColumn].writingBox.top;
break;
default:
ASSERT(!lm);
return E_INVALIDARG;
}
index++;
cCharacters++;
}
// Average the y positions
pls->PtA.y = (LONG) (flTotalY / cCharacters);
pls->PtB.y = pls->PtA.y;
// Set the x range based on the updated reco range
pls->PtA.x = vrc->pLattice->pAltList[wispalt->pColumnIndex[pRecoRange->iwcBegin]].alts[wispalt->pIndexInColumn[pRecoRange->iwcBegin]].writingBox.left;
pls->PtB.x = vrc->pLattice->pAltList[wispalt->pColumnIndex[pRecoRange->iwcBegin+pRecoRange->cCount-1]].alts[wispalt->pIndexInColumn[pRecoRange->iwcBegin+pRecoRange->cCount-1]].writingBox.right;
return hr;
}
HRESULT WINAPI GetGuideIndex(HRECOALT hrcalt, RECO_RANGE* pRecoRange, ULONG *piIndex)
{
struct WispAlternate *wispalt;
struct WispContext *wisphrc;
VRC *vrc;
// find the handle and validate the correpsonding pointer
wispalt = (struct WispAlternate*)FindTpgHandle((HANDLE)hrcalt, TPG_HRECOALT);
if (NULL == wispalt)
{
return E_INVALIDARG;
}
// validate the corresponding hrc pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)wispalt->hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_INVALIDARG;
}
vrc = (VRC *) wisphrc->hrc;
if (vrc == NULL)
{
return E_INVALIDARG;
}
if (IsBadWritePtr(pRecoRange, sizeof(RECO_RANGE)))
{
return E_POINTER;
}
if (IsBadWritePtr(piIndex, sizeof(ULONG)))
{
return E_POINTER;
}
if (!pRecoRange->cCount)
{
return E_INVALIDARG;
}
if (pRecoRange->iwcBegin + pRecoRange->cCount > (ULONG)wispalt->iLength)
{
return E_INVALIDARG;
}
if (!wisphrc->bIsBoxed)
{
return TPC_E_NOT_RELEVANT;
}
// Ok we are clean
pRecoRange->cCount = 1;
// Find the Guide index for this character
*piIndex = wisphrc->uiGuideIndex;
*piIndex += vrc->pLattice->pStroke[wispalt->pColumnIndex[pRecoRange->iwcBegin]].iBox;
// We should not have any spaces in boxed mode. But just in case, let's try to deal with
// them in a reasonable way, by assuming the space comes in the box immediately after
// the box containing the stroke.
if (wispalt->pIndexInColumn[pRecoRange->iwcBegin] == SPACE_ALT_ID)
{
(*piIndex)++;
}
return S_OK;
}
// If the specified character is a space or on the current path, return medium
// confidence. Otherwise return poor.
CONFIDENCE_LEVEL GetConfidenceLevelInternal(VRC *vrc, int iColumn, int iAlt)
{
if (iAlt == SPACE_ALT_ID || vrc->pLattice->pAltList[iColumn].alts[iAlt].fCurrentPath)
{
return CFL_INTERMEDIATE;
}
else
{
return CFL_POOR;
}
}
HRESULT WINAPI GetConfidenceLevel(HRECOALT hrcalt, RECO_RANGE* pRecoRange, CONFIDENCE_LEVEL* pcl)
{
struct WispAlternate *wispalt;
struct WispContext *wisphrc;
VRC *vrc;
// find the handle and validate the correpsonding pointer
wispalt = (struct WispAlternate*)FindTpgHandle((HANDLE)hrcalt, TPG_HRECOALT);
if (NULL == wispalt)
{
return E_INVALIDARG;
}
// validate the corresponding hrc pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)wispalt->hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_INVALIDARG;
}
vrc = (VRC *) wisphrc->hrc;
// Check the parameters
if (pRecoRange != NULL)
{
if (IsBadWritePtr(pRecoRange, sizeof(RECO_RANGE)))
{
return E_POINTER;
}
if (!pRecoRange->cCount)
{
return E_INVALIDARG;
}
if (pRecoRange->iwcBegin + pRecoRange->cCount > (ULONG)wispalt->iLength)
{
return E_INVALIDARG;
}
}
if (IsBadWritePtr(pcl, sizeof(CONFIDENCE_LEVEL)))
{
return E_POINTER;
}
#ifndef ENABLE_CONFIDENCE_LEVEL
// Ok we are clean
return E_NOTIMPL;
#else
if (pRecoRange != NULL)
{
// We only return confidence for single characters
pRecoRange->cCount = 1;
// If the specified character is a space or on the current path, return medium
// confidence. Otherwise return poor.
*pcl = GetConfidenceLevelInternal(vrc, wispalt->pColumnIndex[pRecoRange->iwcBegin], wispalt->pIndexInColumn[pRecoRange->iwcBegin]);
}
else
{
// If the first character is a space or on the current path, return medium
// confidence. Otherwise return poor.
*pcl = GetConfidenceLevelInternal(vrc, wispalt->pColumnIndex[0], wispalt->pIndexInColumn[0]);
}
return S_OK;
#endif
}
HRESULT WINAPI GetPropertyRanges(HRECOALT hrcalt, const GUID *pPropertyGuid, ULONG* pcRanges, RECO_RANGE* pRecoRange)
{
struct WispAlternate *wispalt;
struct WispContext *wisphrc;
VRC *vrc;
// find the handle and validate the correpsonding pointer
wispalt = (struct WispAlternate*)FindTpgHandle((HANDLE)hrcalt, TPG_HRECOALT);
if (NULL == wispalt)
{
return E_INVALIDARG;
}
// validate the corresponding hrc pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)wispalt->hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_INVALIDARG;
}
vrc = (VRC *) wisphrc->hrc;
if (IsBadReadPtr(pPropertyGuid, sizeof(GUID)))
{
return E_POINTER;
}
if (IsBadWritePtr(pcRanges, sizeof(ULONG)))
{
return E_POINTER;
}
if (pRecoRange != NULL && IsBadWritePtr(pRecoRange, sizeof(RECO_RANGE) * (*pcRanges)))
{
return E_POINTER;
}
if (IsEqualGUID(pPropertyGuid, &GUID_LINEMETRICS))
{
return TPC_E_NOT_RELEVANT;
}
#ifdef ENABLE_CONFIDENCE_LEVEL
if (IsEqualGUID(pPropertyGuid, &GUID_CONFIDENCELEVEL))
{
CONFIDENCE_LEVEL clPrev, clThis;
int iRange = 0;
int i;
for (i = 0; i < wispalt->iLength; i++)
{
clThis = GetConfidenceLevelInternal(vrc, wispalt->pColumnIndex[i], wispalt->pIndexInColumn[i]);
if (i == 0 || (clPrev != clThis))
{
iRange++;
}
clPrev = clThis;
}
if (pRecoRange != NULL && *pcRanges < (ULONG) iRange)
{
return TPC_E_INSUFFICIENT_BUFFER;
}
*pcRanges = iRange;
if (pRecoRange != NULL)
{
iRange = 0;
for (i = 0; i < wispalt->iLength; i++)
{
clThis = GetConfidenceLevelInternal(vrc, wispalt->pColumnIndex[i], wispalt->pIndexInColumn[i]);
if (i == 0 || (clPrev != clThis))
{
pRecoRange[iRange].iwcBegin = i;
pRecoRange[iRange].cCount = 1;
iRange++;
}
else
{
pRecoRange[iRange - 1].cCount++;
}
clPrev = clThis;
}
}
return S_OK;
}
#endif
return TPC_E_INVALID_PROPERTY;
}
HRESULT WINAPI GetRangePropertyValue(HRECOALT hrcalt, const GUID *pPropertyGuid, RECO_RANGE* pRecoRange, ULONG*pcbSize, BYTE* pProperty)
{
struct WispAlternate *wispalt;
struct WispContext *wisphrc;
VRC *vrc;
// find the handle and validate the correpsonding pointer
wispalt = (struct WispAlternate*)FindTpgHandle((HANDLE)hrcalt, TPG_HRECOALT);
if (NULL == wispalt)
{
return E_INVALIDARG;
}
// validate the corresponding hrc pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)wispalt->hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_INVALIDARG;
}
vrc = (VRC *) wisphrc->hrc;
if (IsBadReadPtr(pPropertyGuid, sizeof(GUID)))
{
return E_POINTER;
}
if (IsBadWritePtr(pRecoRange, sizeof(RECO_RANGE)))
{
return E_POINTER;
}
if (IsBadWritePtr(pcbSize, sizeof(ULONG)))
{
return E_POINTER;
}
if (pProperty != NULL && IsBadWritePtr(pProperty, *pcbSize))
{
return E_POINTER;
}
if (IsEqualGUID(pPropertyGuid, &GUID_LINEMETRICS))
{
HRESULT hr = S_OK;
LINE_SEGMENT baseline, midline;
if (pProperty == NULL)
{
*pcbSize = sizeof(LATTICE_METRICS);
}
else if (*pcbSize < sizeof(LATTICE_METRICS))
{
return TPC_E_INSUFFICIENT_BUFFER;
}
*pcbSize = sizeof(LATTICE_METRICS);
hr = GetMetrics(hrcalt, pRecoRange, LM_BASELINE, &baseline);
if (SUCCEEDED(hr))
{
hr = GetMetrics(hrcalt, pRecoRange, LM_MIDLINE, &midline);
}
if (SUCCEEDED(hr) && pProperty != NULL)
{
LATTICE_METRICS *plm = (LATTICE_METRICS *) pProperty;
plm->lsBaseline = baseline;
plm->iMidlineOffset = (short)(midline.PtA.y - baseline.PtA.y);
}
return hr;
}
#ifdef ENABLE_CONFIDENCE_LEVEL
if (IsEqualGUID(pPropertyGuid, &GUID_CONFIDENCELEVEL))
{
CONFIDENCE_LEVEL cl;
int iStart = pRecoRange->iwcBegin;
int iLimit = pRecoRange->iwcBegin + pRecoRange->cCount;
int i;
if (pProperty == NULL)
{
*pcbSize = sizeof(CONFIDENCE_LEVEL);
}
else if (*pcbSize < sizeof(CONFIDENCE_LEVEL))
{
return TPC_E_INSUFFICIENT_BUFFER;
}
*pcbSize = sizeof(CONFIDENCE_LEVEL);
cl = GetConfidenceLevelInternal(vrc, wispalt->pColumnIndex[iStart],
wispalt->pIndexInColumn[iStart]);
for (i = iStart + 1; i < iLimit; i++)
{
if (GetConfidenceLevelInternal(vrc, wispalt->pColumnIndex[i], wispalt->pIndexInColumn[i]) != cl)
{
pRecoRange->cCount = i - iStart;
break;
}
}
if (pProperty != NULL)
{
*((CONFIDENCE_LEVEL *) pProperty) = cl;
}
return S_OK;
}
#endif
return TPC_E_INVALID_PROPERTY;
}
void SortLatticeElements(RECO_LATTICE_ELEMENT *pStartElement, RECO_LATTICE_ELEMENT *pCurrent)
{
RECO_LATTICE_ELEMENT rleTemp;
BOOL bSwap = TRUE;
int iElementCount = pCurrent - pStartElement;
int i = 0, count = 0;
// For now just a quick bubble sort
count = 1;
while (bSwap)
{
bSwap = FALSE;
for (i = 0; i < iElementCount-count; i++)
{
if (pStartElement[i].score > pStartElement[i+1].score)
{
// swap
rleTemp = pStartElement[i];
pStartElement[i] = pStartElement[i+1];
pStartElement[i+1] = rleTemp;
bSwap = TRUE;
}
}
count++;
}
}
// GetLatticePtr
//
// Description: This method creates a Lattice structure for
// the recognition context and returns a pointer to it. The
// structure is going to be freed when the recognition
// context is destoyed or when a new call to GetLatticePtr
// is issued.
HRESULT WINAPI GetLatticePtr(HRECOCONTEXT hrc, RECO_LATTICE **ppLattice)
{
BOOL fNextColumnSpace = FALSE;
HRESULT hr = S_OK;
struct WispContext *wisphrc;
RECO_LATTICE_ELEMENT *pCurrent = NULL, *pStartElement = NULL, rleInPath;
int *pMapToLatticeColumn = NULL;
VRC *vrc = NULL;
int i = 0, j = 0, k = 0;
ULONG ulElementCount = 0, ulRealElementCount = 0;
ULONG ulMaxStroke = 0;
ULONG *pCurrentStroke = NULL;
ULONG ulBestResultIndex = 0;
RECO_LATTICE_ELEMENT *pCur = NULL;
int iStroke;
int iExternalColumn;
BYTE *pCurrentPropertyValue = NULL;
RECO_LATTICE_PROPERTY *pCurrentProperty = NULL;
RECO_LATTICE_PROPERTY *pConfidencePropStart = NULL;
RECO_LATTICE_PROPERTY **ppCurrentProperty = NULL;
LATTICE_METRICS *pLatticeMetrics;
FLOAT flScore;
// validate and destroy the handle & return the pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (NULL == wisphrc)
{
return E_INVALIDARG;
}
// Check the parameters
if (IsBadWritePtr(ppLattice, sizeof(RECO_LATTICE*)))
{
return E_POINTER;
}
*ppLattice = NULL;
// We should only do this if the lattice is dirty!
if (wisphrc->pLattice)
{
hr = FreeRecoLattice(wisphrc);
ASSERT(SUCCEEDED(hr));
hr = S_OK;
}
// Do we have results?
if (!wisphrc->hrc)
{
return TPC_E_NOT_RELEVANT;
}
vrc = (VRC*) wisphrc->hrc;
if (!vrc->pLatticePath)
{
return TPC_E_NOT_RELEVANT;
}
// Allocate the lattice
wisphrc->pLattice = (RECO_LATTICE*)ExternAlloc(sizeof(RECO_LATTICE));
if (!wisphrc->pLattice)
{
return E_OUTOFMEMORY;
}
// Initialize the RECO_LATTICE structure
ZeroMemory(wisphrc->pLattice, sizeof(RECO_LATTICE));
wisphrc->pLattice->pGuidProperties = NULL;
wisphrc->pLattice->ulPropertyCount = 0;
wisphrc->pLattice->ulColumnCount = vrc->pLattice->nStrokes;
wisphrc->pLattice->ulBestResultColumnCount = vrc->pLatticePath->nChars;
// Add columns to the lattice for each space
for (i = 0; i < vrc->pLattice->nStrokes; i++)
{
if (vrc->pLattice->pAltList[i].fSpaceAfterStroke)
{
wisphrc->pLattice->ulColumnCount++;
}
}
// For now we have only two properties: the GUID_CONFIDENCELEVEL and GUID_LINEMETRICS
wisphrc->pLattice->ulPropertyCount = 1;
#ifdef ENABLE_CONFIDENCE_LEVEL
wisphrc->pLattice->ulPropertyCount++;
#endif
wisphrc->pLattice->pGuidProperties = (GUID *) ExternAlloc(wisphrc->pLattice->ulPropertyCount * sizeof(GUID));
if (wisphrc->pLattice->pGuidProperties == NULL)
{
HRESULT hrFRL = FreeRecoLattice(wisphrc);
ASSERT(SUCCEEDED(hrFRL));
return E_OUTOFMEMORY;
}
wisphrc->pLattice->pGuidProperties[0] = GUID_LINEMETRICS;
#ifdef ENABLE_CONFIDENCE_LEVEL
wisphrc->pLattice->pGuidProperties[1] = GUID_CONFIDENCELEVEL;
#endif
if (wisphrc->pLattice->ulColumnCount)
{
// Allocating the array of LatticeColumns
wisphrc->pLattice->pLatticeColumns =
ExternAlloc(wisphrc->pLattice->ulColumnCount * sizeof(RECO_LATTICE_COLUMN));
if (wisphrc->pLattice->pLatticeColumns)
{
ZeroMemory(wisphrc->pLattice->pLatticeColumns,
wisphrc->pLattice->ulColumnCount * sizeof(RECO_LATTICE_COLUMN));
}
// Allocate the arrays for the best result
wisphrc->pLattice->pulBestResultColumns = (ULONG*)
ExternAlloc(vrc->pLatticePath->nChars * sizeof(ULONG));
wisphrc->pLattice->pulBestResultIndexes = (ULONG*)
ExternAlloc(vrc->pLatticePath->nChars * sizeof(ULONG));
if (!wisphrc->pLattice->pLatticeColumns ||
!wisphrc->pLattice->pulBestResultColumns ||
!wisphrc->pLattice->pulBestResultIndexes)
{
HRESULT hrFRL = FreeRecoLattice(wisphrc);
ASSERT(SUCCEEDED(hrFRL));
return E_OUTOFMEMORY;
}
// Allocating the array of Strokes
wisphrc->pLattice->pLatticeColumns[0].pStrokes =
ExternAlloc(vrc->pLattice->nRealStrokes * sizeof(ULONG));
if (!wisphrc->pLattice->pLatticeColumns[0].pStrokes)
{
HRESULT hrFRL = FreeRecoLattice(wisphrc);
ASSERT(SUCCEEDED(hrFRL));
return E_OUTOFMEMORY;
}
// Do corrections for the merged strokes - Annoying detail!
j = 0;
for (i = 0; i < vrc->pLattice->nStrokes; i++)
{
if (vrc->pLattice->pStroke[i].iLast != vrc->pLattice->pStroke[i].iOrder)
{
//There has been Stroke merging
// Add the Stroke list for this merge stroke
for (k = vrc->pLattice->pStroke[i].iOrder; k <= vrc->pLattice->pStroke[i].iLast; k++)
{
wisphrc->pLattice->pLatticeColumns[0].pStrokes[j] = k;
j++;
}
}
else
{
// No stroke merging for this stroke
wisphrc->pLattice->pLatticeColumns[0].pStrokes[j] =
vrc->pLattice->pStroke[i].iOrder;
j++;
}
}
// Count the number of Lattice elements
for (i = 0; i < vrc->pLattice->nStrokes; i++)
{
unsigned int ulElements = vrc->pLattice->pAltList[i].nUsed;
// For each column count the elements
if ((wisphrc->dwFlags & RECOFLAG_SINGLESEG) != 0)
{
int nStrokes = -1;
ulElements = 0;
for (j = 0; j < vrc->pLattice->pAltList[i].nUsed; j++)
{
if (vrc->pLattice->pAltList[i].alts[j].fCurrentPath)
{
nStrokes = vrc->pLattice->pAltList[i].alts[j].nStrokes;
break;
}
}
for (j = 0; j < vrc->pLattice->pAltList[i].nUsed; j++)
{
if (nStrokes == vrc->pLattice->pAltList[i].alts[j].nStrokes)
{
ulElements++;
}
}
}
ulElementCount += ulElements;
ulRealElementCount += ulElements;
// Add an element for each space
if (vrc->pLattice->pAltList[i].fSpaceAfterStroke)
{
ulElementCount++;
}
}
// Create the elements if needed
if (ulElementCount)
{
wisphrc->pLattice->pLatticeColumns[0].pLatticeElements
= ExternAlloc(ulElementCount*sizeof(RECO_LATTICE_ELEMENT));
if (!wisphrc->pLattice->pLatticeColumns[0].pLatticeElements)
{
HRESULT hrFRL = FreeRecoLattice(wisphrc);
ASSERT(SUCCEEDED(hrFRL));
return E_OUTOFMEMORY;
}
ZeroMemory(wisphrc->pLattice->pLatticeColumns[0].pLatticeElements,
ulElementCount*sizeof(RECO_LATTICE_ELEMENT));
pCurrent = wisphrc->pLattice->pLatticeColumns[0].pLatticeElements;
// Let's do the line metrics and the confidence levels
pCurrentProperty =
(RECO_LATTICE_PROPERTY *) ExternAlloc((3 + ulRealElementCount) * sizeof(RECO_LATTICE_PROPERTY));
wisphrc->pLatticeProperties = pCurrentProperty;
pCurrentPropertyValue =
(BYTE *) ExternAlloc(3 * sizeof(CONFIDENCE_LEVEL) + ulRealElementCount * sizeof(LATTICE_METRICS));
wisphrc->pLatticePropertyValues = pCurrentPropertyValue;
// Allocate property lists for each element. The non-spaces (real elements) each have two
// properties, and the spaces have one property.
#ifdef ENABLE_CONFIDENCE_LEVEL
ppCurrentProperty =
(RECO_LATTICE_PROPERTY **) ExternAlloc((ulElementCount + ulRealElementCount) * sizeof(RECO_LATTICE_PROPERTY *));
#else
ppCurrentProperty =
(RECO_LATTICE_PROPERTY **) ExternAlloc(ulRealElementCount * sizeof(RECO_LATTICE_PROPERTY *));
#endif
wisphrc->ppLatticeProperties = ppCurrentProperty;
if (!pCurrentProperty || !pCurrentPropertyValue || !ppCurrentProperty)
{
HRESULT hrFRL = FreeRecoLattice(wisphrc);
ASSERT(SUCCEEDED(hrFRL));
return E_OUTOFMEMORY;
}
// Fill the RECO_LATTICE_PROPERTY array to contain the confidence level
pConfidencePropStart = pCurrentProperty;
pCurrentProperty->guidProperty = GUID_CONFIDENCELEVEL;
pCurrentProperty->cbPropertyValue = sizeof(CONFIDENCE_LEVEL);
pCurrentProperty->pPropertyValue = pCurrentPropertyValue;
*( (CONFIDENCE_LEVEL*)pCurrentPropertyValue) = CFL_STRONG;
pCurrentPropertyValue += sizeof(CONFIDENCE_LEVEL);
pCurrentProperty++;
// next value
pCurrentProperty->guidProperty = GUID_CONFIDENCELEVEL;
pCurrentProperty->cbPropertyValue = sizeof(CONFIDENCE_LEVEL);
pCurrentProperty->pPropertyValue = pCurrentPropertyValue;
*( (CONFIDENCE_LEVEL*)pCurrentPropertyValue) = CFL_INTERMEDIATE;
pCurrentPropertyValue += sizeof(CONFIDENCE_LEVEL);
pCurrentProperty++;
// next value
pCurrentProperty->guidProperty = GUID_CONFIDENCELEVEL;
pCurrentProperty->cbPropertyValue = sizeof(CONFIDENCE_LEVEL);
pCurrentProperty->pPropertyValue = pCurrentPropertyValue;
*( (CONFIDENCE_LEVEL*)pCurrentPropertyValue) = CFL_POOR;
pCurrentPropertyValue += sizeof(CONFIDENCE_LEVEL);
pCurrentProperty++;
}
// Allocate space for the mapping
pMapToLatticeColumn = (int *) ExternAlloc(sizeof(int) * vrc->pLattice->nStrokes);
if (pMapToLatticeColumn == NULL)
{
HRESULT hrFRL = FreeRecoLattice(wisphrc);
ASSERT(SUCCEEDED(hrFRL));
return E_OUTOFMEMORY;
}
// Fill in mapping from internal lattice columns to the newly created lattice columns.
// Note that this mapping always points to columns related to strokes, not to spaces.
j = 0;
for (i = 0; i < vrc->pLattice->nStrokes; i++)
{
pMapToLatticeColumn[i] = j;
j++;
// Add a column for each space
if (vrc->pLattice->pAltList[i].fSpaceAfterStroke)
{
j++;
}
}
ASSERT( wisphrc->pLattice->ulColumnCount == j );
// Initialize the lattice columns
pCurrentStroke = wisphrc->pLattice->pLatticeColumns[0].pStrokes;
iExternalColumn = 0;
for (i = 0; i < vrc->pLattice->nStrokes; i++)
{
int iStartStroke = i, iEndStroke = vrc->pLattice->nStrokes;
ASSERT(pMapToLatticeColumn[i] == iExternalColumn);
rleInPath.type = RECO_TYPE_WSTRING;
ulMaxStroke = 0;
pStartElement = pCurrent;
// If we're pretending to have a single segmentation, then find the next
// element on the best path, and restrict the search for elements starting
// here to that column.
if ((wisphrc->dwFlags & RECOFLAG_SINGLESEG) != 0)
{
BOOL fFound = FALSE;
for (j = i; j < vrc->pLattice->nStrokes && !fFound; j++)
{
for (k = 0; k < vrc->pLattice->pAltList[j].nUsed && !fFound; k++)
{
if (vrc->pLattice->pAltList[j].alts[k].fCurrentPath)
{
// Make sure this element links up to the starting column we
// are at now. If it doesn't, then the current stroke is in
// the middle of a best path element, so this column will
// be empty.
if (j + 1 - vrc->pLattice->pAltList[j].alts[k].nStrokes != i)
{
goto NoElementsInColumn;
}
iStartStroke = j;
iEndStroke = j + 1;
fFound = TRUE;
}
}
}
if (!fFound)
{
goto NoElementsInColumn;
}
}
// Find all elements that start at this columns #
// This could probably be optimized
for (j = iStartStroke; j < iEndStroke; j++)
{
// Go through each alt
for (k = 0; k < vrc->pLattice->pAltList[j].nUsed; k++)
{
if (j + 1 - vrc->pLattice->pAltList[j].alts[k].nStrokes == i)
{
// This one starts at the right location
// Set up the properties. There are two properties for each
// character, the line metrics and the confidence level.
pCurrent->epProp.cProperties = 1;
ASSERT(pCurrent->epProp.apProps == NULL);
pCurrent->epProp.apProps = ppCurrentProperty;
*ppCurrentProperty = pCurrentProperty;
ppCurrentProperty++;
pCurrentProperty->guidProperty = GUID_LINEMETRICS;
pCurrentProperty->cbPropertyValue = sizeof(LATTICE_METRICS);
pCurrentProperty->pPropertyValue = pCurrentPropertyValue;
pCurrentProperty++;
pLatticeMetrics = (LATTICE_METRICS *) pCurrentPropertyValue;
pCurrentPropertyValue += sizeof(LATTICE_METRICS);
pLatticeMetrics->lsBaseline.PtA.x = vrc->pLattice->pAltList[j].alts[k].writingBox.left;
pLatticeMetrics->lsBaseline.PtA.y = vrc->pLattice->pAltList[j].alts[k].writingBox.bottom;
pLatticeMetrics->lsBaseline.PtB.x = vrc->pLattice->pAltList[j].alts[k].writingBox.right;
pLatticeMetrics->lsBaseline.PtB.y = vrc->pLattice->pAltList[j].alts[k].writingBox.bottom;
pLatticeMetrics->iMidlineOffset =
(SHORT) ((vrc->pLattice->pAltList[j].alts[k].writingBox.top -
vrc->pLattice->pAltList[j].alts[k].writingBox.bottom) / 2);
#ifdef ENABLE_CONFIDENCE_LEVEL
switch (GetConfidenceLevelInternal(vrc, i, k))
{
case CFL_STRONG:
pCurrent->epProp.cProperties++;
*ppCurrentProperty = pConfidencePropStart;
ppCurrentProperty++;
break;
case CFL_INTERMEDIATE:
pCurrent->epProp.cProperties++;
*ppCurrentProperty = pConfidencePropStart + 1;
ppCurrentProperty++;
break;
case CFL_POOR:
pCurrent->epProp.cProperties++;
*ppCurrentProperty = pConfidencePropStart + 2;
ppCurrentProperty++;
break;
}
#endif
// Get the character
if (vrc->pLattice->pAltList[j].alts[k].wChar == SYM_UNKNOWN)
{
pCurrent->pData = (void*) SYM_UNKNOWN;
}
else
{
pCurrent->pData = (void*)(LocRunDense2Unicode(&g_locRunInfo,
vrc->pLattice->pAltList[j].alts[k].wChar));
}
pCurrent->ulNextColumn = pMapToLatticeColumn[j] + 1;
// Count up the number of real strokes used by this alternate
pCurrent->ulStrokeNumber = 0;
// For each merged stroke in this alternate
for (iStroke = j; iStroke > j - vrc->pLattice->pAltList[j].alts[k].nStrokes; iStroke--)
{
// Add the number of real strokes contained in this merged stroke
pCurrent->ulStrokeNumber +=
vrc->pLattice->pStroke[iStroke].iLast -
vrc->pLattice->pStroke[iStroke].iOrder + 1;
}
if (ulMaxStroke < pCurrent->ulStrokeNumber)
ulMaxStroke = pCurrent->ulStrokeNumber;
pCurrent->type = RECO_TYPE_WCHAR;
flScore = -1024 *
vrc->pLattice->pAltList[j].alts[k].logProb;
// GetScore(vrc->pLattice, j, k);
if (flScore > INT_MAX)
{
flScore = (FLOAT) INT_MAX;
}
pCurrent->score = (int) flScore;
// Is it part of the best result?
if (vrc->pLattice->pAltList[j].alts[k].fCurrentPath)
{
// Yes, strore the column
wisphrc->pLattice->pulBestResultColumns[ulBestResultIndex] = iExternalColumn;
ASSERT(rleInPath.type == RECO_TYPE_WSTRING);
rleInPath = *pCurrent;
}
pCurrent++;
}
}
}
// We need to sort that list!
SortLatticeElements(pStartElement, pCurrent);
// Is there an element from the best result in this column?
if (rleInPath.type != RECO_TYPE_WSTRING)
{
// find its index in the column
for (pCur = pStartElement; pCur < pCurrent; pCur++)
{
if (!memcmp(pCur, &rleInPath, sizeof(RECO_LATTICE_ELEMENT)))
break;
}
ASSERT(pCur != pCurrent);
if (pCur != pCurrent)
{
wisphrc->pLattice->pulBestResultIndexes[ulBestResultIndex] = pCur - pStartElement;
ulBestResultIndex++;
}
}
NoElementsInColumn:
// Fill in the Reco Column information
wisphrc->pLattice->pLatticeColumns[iExternalColumn].key = iExternalColumn;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].cpProp.cProperties = 0;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].cpProp.apProps = NULL;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].cStrokes = ulMaxStroke;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].pStrokes = pCurrentStroke;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].cLatticeElements = pCurrent-pStartElement;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].pLatticeElements = pStartElement;
// Jump to the next "current" stroke : Always the annoying detail!
pCurrentStroke += vrc->pLattice->pStroke[i].iLast -
vrc->pLattice->pStroke[i].iOrder + 1;
// The new Start is:
pStartElement = pCurrent;
iExternalColumn++;
if (vrc->pLattice->pAltList[i].fSpaceAfterStroke)
{
// If there is a space, then it must be on the current path (because spaces are only
// created on the current path). This simplifies the code a lot.
pStartElement = pCurrent;
// Set up the properties. For spaces, the only property that applies is the
// confidence level.
pCurrent->epProp.cProperties = 0;
ASSERT(pCurrent->epProp.apProps == NULL);
pCurrent->epProp.apProps = ppCurrentProperty;
#ifdef ENABLE_CONFIDENCE_LEVEL
switch (GetConfidenceLevelInternal(vrc, i, SPACE_ALT_ID))
{
case CFL_STRONG:
pCurrent->epProp.cProperties++;
*ppCurrentProperty = pConfidencePropStart;
ppCurrentProperty++;
break;
case CFL_INTERMEDIATE:
pCurrent->epProp.cProperties++;
*ppCurrentProperty = pConfidencePropStart + 1;
ppCurrentProperty++;
break;
case CFL_POOR:
pCurrent->epProp.cProperties++;
*ppCurrentProperty = pConfidencePropStart + 2;
ppCurrentProperty++;
break;
}
#endif
pCurrent->pData = (void*) SYM_SPACE;
pCurrent->ulNextColumn = iExternalColumn + 1;
pCurrent->ulStrokeNumber = 0;
pCurrent->type = RECO_TYPE_WCHAR;
pCurrent->score = 0;
wisphrc->pLattice->pulBestResultColumns[ulBestResultIndex] = iExternalColumn;
wisphrc->pLattice->pulBestResultIndexes[ulBestResultIndex] = 0;
ulBestResultIndex++;
pCurrent++;
// Fill in the Reco Column information
wisphrc->pLattice->pLatticeColumns[iExternalColumn].key = iExternalColumn;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].cpProp.cProperties = 0;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].cpProp.apProps = NULL;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].cStrokes = 0;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].pStrokes = pCurrentStroke;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].cLatticeElements = 1;
wisphrc->pLattice->pLatticeColumns[iExternalColumn].pLatticeElements = pStartElement;
// The new Start is:
pStartElement = pCurrent;
iExternalColumn++;
}
}
// Check the number of elements in the best path
ASSERT(ulBestResultIndex == (ULONG)vrc->pLatticePath->nChars);
ASSERT(iExternalColumn == wisphrc->pLattice->ulColumnCount);
ASSERT(pCurrentStroke - wisphrc->pLattice->pLatticeColumns[0].pStrokes == vrc->pLattice->nRealStrokes);
}
if (SUCCEEDED(hr))
*ppLattice = wisphrc->pLattice;
ExternFree(pMapToLatticeColumn);
return hr;
}
// Lists of properties
static const ULONG CONTEXT_PROPERTIES_COUNT = 1;
// {1ABC3828-BDF1-4ef3-8F2C-0751EC0DE742}
static const GUID GUID_ENABLE_IFELANG3 = { 0x1abc3828, 0xbdf1, 0x4ef3, { 0x8f, 0x2c, 0x7, 0x51, 0xec, 0xd, 0xe7, 0x42 } };
// GetContextPropertyList
// Return a list of properties supported on the context
//
// Parameters:
// hrc [in] : Handle to the recognition context
// pcProperties [in/out] : Number of properties supported
// pPropertyGUIDS [out] : List of properties supported
HRESULT WINAPI GetContextPropertyList(HRECOCONTEXT hrc,
ULONG* pcProperties,
GUID* pPropertyGUIDS)
{
if (NULL == (HRC *)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT) )
{
return E_POINTER;
}
if ( IsBadWritePtr(pcProperties, sizeof(ULONG)) )
return E_POINTER;
if (pPropertyGUIDS == NULL) // Need only the count
{
*pcProperties = CONTEXT_PROPERTIES_COUNT;
return S_OK;
}
if (*pcProperties < CONTEXT_PROPERTIES_COUNT)
return TPC_E_INSUFFICIENT_BUFFER;
*pcProperties = CONTEXT_PROPERTIES_COUNT;
if ( IsBadWritePtr(pPropertyGUIDS, CONTEXT_PROPERTIES_COUNT * sizeof(GUID)) )
return E_POINTER;
pPropertyGUIDS[0] = GUID_ENABLE_IFELANG3;
return S_OK;
}
// GetContextPropertyValue
// Return a property of the context, currently no properties are supported
//
// Parameters:
// hrc [in] : Handle to the recognition context
// pGuid [in] : Property GUID
// pcbSize [in/out] : Size of the property buffer (in BYTEs)
// pProperty [out] : Value of the desired property
HRESULT WINAPI GetContextPropertyValue(HRECOCONTEXT hrc,
GUID *pGuid,
ULONG *pcbSize,
BYTE *pProperty)
{
struct WispContext *wisphrc;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_POINTER;
}
if ( IsBadReadPtr(pGuid, sizeof(GUID)) )
return E_POINTER;
if ( IsBadWritePtr(pcbSize, sizeof(ULONG)) )
return E_POINTER;
if ( IsEqualGUID(pGuid, &GUID_ENABLE_IFELANG3) )
{
BOOL *pb = (BOOL *) pProperty;
if (pProperty == NULL)
{
*pcbSize = sizeof(BOOL);
return S_OK;
}
if (*pcbSize < sizeof(BOOL))
{
return TPC_E_INSUFFICIENT_BUFFER;
}
*pcbSize = sizeof(BOOL);
#ifdef USE_IFELANG3
*pb = LatticeIFELang3Available();
#else
*pb = FALSE;
#endif
return S_OK;
}
return TPC_E_INVALID_PROPERTY;
}
// SetContextPropertyValue
// Set a property of the context (currently only GUID_ENABLE_IFELANG3)
//
// Parameters:
// hrc [in] : Handle to the recognition context
// pGuid [in] : Property GUID
// pcbSize [in] : Size of the property buffer (in BYTEs)
// pProperty [in] : Value of the desired property
HRESULT WINAPI SetContextPropertyValue(HRECOCONTEXT hrc,
GUID *pGuid,
ULONG cbSize,
BYTE *pProperty)
{
struct WispContext *wisphrc;
// find the handle and validate the correpsonding pointer
wisphrc = (struct WispContext*)FindTpgHandle((HANDLE)hrc, TPG_HRECOCONTEXT);
if (wisphrc == NULL)
{
return E_POINTER;
}
if ( IsBadReadPtr(pGuid, sizeof(GUID)) )
return E_POINTER;
if ( IsBadReadPtr(pProperty, cbSize) )
return E_POINTER;
if ( IsEqualGUID(pGuid, &GUID_ENABLE_IFELANG3) )
{
BOOL *pb = (BOOL *) pProperty;
if (cbSize != sizeof(BOOL))
{
return E_INVALIDARG;
}
if (*pb)
{
#ifdef USE_IFELANG3
// If already enabled, return S_FALSE
if (LatticeIFELang3Available())
{
return S_FALSE;
}
return LatticeConfigIFELang3() ? S_OK : E_FAIL;
#else
return E_FAIL;
#endif
}
else
{
#ifdef USE_IFELANG3
// If already disabled, return S_FALSE
if (!LatticeIFELang3Available())
{
return S_FALSE;
}
return LatticeUnconfigIFELang3() ? S_OK : E_FAIL;
#else
return S_FALSE;
#endif
}
}
return TPC_E_INVALID_PROPERTY;
}
/////////////////////////////////////////////////////////////////
// Registration information
//
//
#define FULL_PATH_VALUE L"Recognizer dll"
#define RECO_LANGUAGES L"Recognized Languages"
#define RECO_CAPABILITIES L"Recognizer Capability Flags"
#define RECO_MANAGER_KEY L"CLSID\\{DE815B00-9460-4F6E-9471-892ED2275EA5}\\InprocServer32"
#define CLSID_KEY L"CLSID"
/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer - Adds entries to the system registry
// This recognizer GUID is going to be
// {6D0087D7-61D2-495f-9293-5B7B1C3FCEAB}
// Each recognizer HAS to have a different GUID
STDAPI DllRegisterServer(void)
{
HKEY hKeyReco = NULL;
HKEY hKeyRecoManager = NULL;
LONG lRes = 0;
HKEY hkeyMyReco = NULL;
DWORD dwLength = 0, dwType = 0, dwSize = 0;
DWORD dwDisposition;
WCHAR szRecognizerPath[MAX_PATH];
WCHAR *RECO_SUBKEY = NULL, *RECOGNIZER_SUBKEY = NULL;
WCHAR *RECOPROC_SUBKEY = NULL, *RECOCLSID_SUBKEY = NULL;
RECO_ATTRS recoAttr;
HRESULT hr = S_OK;
HRECOGNIZER hrec;
if (FAILED(CreateRecognizer(NULL, &hrec)))
{
return E_FAIL;
}
hr = GetRecoAttributes(hrec, &recoAttr);
if (FAILED(hr))
{
return E_FAIL;
}
if (FAILED(DestroyRecognizer(hrec)))
{
return E_FAIL;
}
if (recoAttr.awLanguageId[0] == MAKELANGID(LANG_JAPANESE, SUBLANG_NEUTRAL))
{
RECO_SUBKEY = L"Software\\Microsoft\\TPG\\System Recognizers\\{6D4087D7-61D2-495f-9293-5B7B1C3FCEAB}";
RECOGNIZER_SUBKEY = L"CLSID\\{6D4087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOPROC_SUBKEY = L"{6D4087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOCLSID_SUBKEY = L"{6D4087D7-61D2-495f-9293-5B7B1C3FCEAB}";
}
if (recoAttr.awLanguageId[0] == MAKELANGID(LANG_KOREAN, SUBLANG_NEUTRAL))
{
RECO_SUBKEY = L"Software\\Microsoft\\TPG\\System Recognizers\\{6D5087D7-61D2-495f-9293-5B7B1C3FCEAB}";
RECOGNIZER_SUBKEY = L"CLSID\\{6D5087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOPROC_SUBKEY = L"{6D5087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOCLSID_SUBKEY = L"{6D5087D7-61D2-495f-9293-5B7B1C3FCEAB}";
}
if (recoAttr.awLanguageId[0] == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED))
{
RECO_SUBKEY = L"Software\\Microsoft\\TPG\\System Recognizers\\{6D6087D7-61D2-495f-9293-5B7B1C3FCEAB}";
RECOGNIZER_SUBKEY = L"CLSID\\{6D6087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOPROC_SUBKEY = L"{6D6087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOCLSID_SUBKEY = L"{6D6087D7-61D2-495f-9293-5B7B1C3FCEAB}";
}
if (recoAttr.awLanguageId[0] == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL))
{
RECO_SUBKEY = L"Software\\Microsoft\\TPG\\System Recognizers\\{6D7087D7-61D2-495f-9293-5B7B1C3FCEAB}";
RECOGNIZER_SUBKEY = L"CLSID\\{6D7087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOPROC_SUBKEY = L"{6D7087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOCLSID_SUBKEY = L"{6D7087D7-61D2-495f-9293-5B7B1C3FCEAB}";
}
// Write the path to this dll in the registry under
// the recognizer subkey
// Wipe out the previous values
lRes = RegDeleteKeyW(HKEY_LOCAL_MACHINE, RECO_SUBKEY);
// Create the new key
lRes = RegCreateKeyExW(HKEY_LOCAL_MACHINE, RECO_SUBKEY, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyMyReco, &dwDisposition);
ASSERT(lRes == ERROR_SUCCESS);
if (lRes != ERROR_SUCCESS)
{
if (hkeyMyReco)
RegCloseKey(hkeyMyReco);
return E_FAIL;
}
// Get the current path
// Try to get the path of the RecoObj.dll
// It should be the same as the one for the RecoCom.dll
dwLength = GetModuleFileNameW((HMODULE)g_hInstanceDllCode, szRecognizerPath, MAX_PATH);
if (dwLength == 0 || (dwLength == MAX_PATH && szRecognizerPath[MAX_PATH - 1] != 0))
{
RegCloseKey(hkeyMyReco);
return E_FAIL;
}
// Write the path to the dll as a value
lRes = RegSetValueExW(hkeyMyReco, FULL_PATH_VALUE, 0, REG_SZ,
(BYTE*)szRecognizerPath, sizeof(WCHAR)*(wcslen(szRecognizerPath)+1));
ASSERT(lRes == ERROR_SUCCESS);
if (lRes != ERROR_SUCCESS)
{
RegCloseKey(hkeyMyReco);
return E_FAIL;
}
// Add the reco attribute information
lRes = RegSetValueExW(hkeyMyReco, RECO_LANGUAGES, 0, REG_BINARY,
(BYTE*)recoAttr.awLanguageId, 64 * sizeof(WORD));
ASSERT(lRes == ERROR_SUCCESS);
if (lRes != ERROR_SUCCESS)
{
RegCloseKey(hkeyMyReco);
return E_FAIL;
}
lRes = RegSetValueExW(hkeyMyReco, RECO_CAPABILITIES, 0, REG_DWORD,
(BYTE*)&(recoAttr.dwRecoCapabilityFlags), sizeof(DWORD));
ASSERT(lRes == ERROR_SUCCESS);
if (lRes != ERROR_SUCCESS)
{
RegCloseKey(hkeyMyReco);
return E_FAIL;
}
RegCloseKey(hkeyMyReco);
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
LONG lRes1 = 0;
// get language id
WCHAR *RECO_SUBKEY = NULL, *RECOGNIZER_SUBKEY = NULL;
WCHAR *RECOPROC_SUBKEY = NULL, *RECOCLSID_SUBKEY = NULL;
RECO_ATTRS recoAttr;
HRESULT hr = S_OK;
HRECOGNIZER hrec;
if (FAILED(CreateRecognizer(NULL, &hrec)))
{
return E_FAIL;
}
hr = GetRecoAttributes(hrec, &recoAttr);
if (FAILED(hr))
{
return E_FAIL;
}
if (FAILED(DestroyRecognizer(hrec)))
{
return E_FAIL;
}
if (recoAttr.awLanguageId[0] == MAKELANGID(LANG_JAPANESE, SUBLANG_NEUTRAL))
{
RECO_SUBKEY = L"Software\\Microsoft\\TPG\\System Recognizers\\{6D4087D7-61D2-495f-9293-5B7B1C3FCEAB}";
RECOGNIZER_SUBKEY = L"CLSID\\{6D4087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOPROC_SUBKEY = L"{6D4087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOCLSID_SUBKEY = L"{6D4087D7-61D2-495f-9293-5B7B1C3FCEAB}";
}
if (recoAttr.awLanguageId[0] == MAKELANGID(LANG_KOREAN, SUBLANG_NEUTRAL))
{
RECO_SUBKEY = L"Software\\Microsoft\\TPG\\System Recognizers\\{6D5087D7-61D2-495f-9293-5B7B1C3FCEAB}";
RECOGNIZER_SUBKEY = L"CLSID\\{6D5087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOPROC_SUBKEY = L"{6D5087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOCLSID_SUBKEY = L"{6D5087D7-61D2-495f-9293-5B7B1C3FCEAB}";
}
if (recoAttr.awLanguageId[0] == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED))
{
RECO_SUBKEY = L"Software\\Microsoft\\TPG\\System Recognizers\\{6D6087D7-61D2-495f-9293-5B7B1C3FCEAB}";
RECOGNIZER_SUBKEY = L"CLSID\\{6D6087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOPROC_SUBKEY = L"{6D6087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOCLSID_SUBKEY = L"{6D6087D7-61D2-495f-9293-5B7B1C3FCEAB}";
}
if (recoAttr.awLanguageId[0] == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL))
{
RECO_SUBKEY = L"Software\\Microsoft\\TPG\\System Recognizers\\{6D7087D7-61D2-495f-9293-5B7B1C3FCEAB}";
RECOGNIZER_SUBKEY = L"CLSID\\{6D7087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOPROC_SUBKEY = L"{6D7087D7-61D2-495f-9293-5B7B1C3FCEAB}\\InprocServer32";
RECOCLSID_SUBKEY = L"{6D7087D7-61D2-495f-9293-5B7B1C3FCEAB}";
}
// Wipe out the registry information
lRes1 = RegDeleteKeyW(HKEY_LOCAL_MACHINE, RECO_SUBKEY);
// Try to erase the local machine\software\microsoft\tpg\recognizer
// if necessary (don't care if it fails)
RegDeleteKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\TPG\\System Recognizers");
RegDeleteKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\TPG");
if (lRes1 != ERROR_SUCCESS && lRes1 != ERROR_FILE_NOT_FOUND)
{
return E_FAIL;
}
return S_OK ;
}
/*************************************************
* NAME: validateTpgHandle
*
* Generic function to validate a pointer obtained from a WISP
* style handle. For now function checks the memory
* is writable
*
* RETURNS
* TRUE if the pointer passes a minimal validation
*
*************************************************/
BOOL validateTpgHandle(void *pPtr, int type)
{
BOOL bRet = FALSE;
switch (type)
{
case TPG_HRECOCONTEXT:
{
if (0 == IsBadWritePtr(pPtr, sizeof(struct WispContext)))
{
bRet = TRUE;
}
break;
}
case TPG_HRECOGNIZER:
{
if (0 == IsBadWritePtr(pPtr, sizeof(struct WispRec)))
{
bRet = TRUE;
}
break;
}
case TPG_HRECOALT:
{
if (0 == IsBadWritePtr(pPtr, sizeof(struct WispAlternate)))
{
bRet = TRUE;
}
break;
}
default:
break;
}
return bRet;
}