2025-04-27 07:49:33 -04:00

436 lines
12 KiB
C++

/////////////////////////////////////////////////////////////////////
//
// MODULE: SERVCHAN.CPP
//
// PURPOSE: Provides the implementation of the
// CStatChanRecordProcessor class
// These methods parse and collection schedule and channel
// data that is then stored into the GuideStore using the
// gsServices and gsChannels methods.
//
/////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "errcodes.h"
#include <Afxtempl.h>
#include <crtdbg.h>
#include <fstream.h>
#include <fcntl.h>
#include <io.h>
#include <string.h>
#include "guidestore.h"
#include "services.h"
#include "channels.h"
#include "programs.h"
#include "schedules.h"
#include "wtmsload.h"
#include "tmsparse.h"
#include "servchan.h"
#define TIMING 0
#include "..\..\timing.h"
#ifdef _DUMP_LOADER
CString csDiagMil;
extern HANDLE hDiagFile;
extern char szDiagBuff[1024];
int ChannelCnt = 0;
int TimeSlotCnt = 0;
extern DWORD dwBytesWritten;
#endif
SDataFileFields ssfStatChanFieldInfo[StatChanRec_Fields] =
{
TRUE, 10,
TRUE, 40,
TRUE, 5,
TRUE, 10,
TRUE, 10
};
// CStatChanRecordProcessor
//
CStatChanRecordProcessor::CStatChanRecordProcessor(int nNumFields,
SDataFileFields ssfFieldsInfo[])
{
m_Init();
m_pFieldsDesc = ssfFieldsInfo;
m_nNumFields = nNumFields;
m_ChannelIDMap.InitHashTable(MAX_CHANNELS, TRUE);
}
CStatChanRecordProcessor::CStatChanRecordProcessor()
{
m_Init();
m_pFieldsDesc = ssfStatChanFieldInfo;
m_nNumFields = StatChanRec_Fields;
m_ChannelIDMap.InitHashTable(MAX_CHANNELS, TRUE);
}
/////////////////////////////////////////////////////////////////////////
//
// METHOD: m_Process
//
// PARAMETERS: [IN] lpData - Data to be processed
// [IN] nDataSize - Size of data
//
// PURPOSE: Processes the Data stream for Channel records
// Once Channel records have been parsed and
// prepared for table updation signals end of channel records
// to the file processor
//
/////////////////////////////////////////////////////////////////////////
//
int CStatChanRecordProcessor::m_Process(LPCTSTR lpData, int nDataSize, int* pBytesProcessed)
{
int nFields = 0;
int nFieldSize = 0;
int nParsePos = 0;
int nBytesProcessed = 0;
// Parameter validation
//
if (NULL == lpData || 0 == nDataSize)
{
return ERROR_INVALID_ARGS;
}
else
{
*pBytesProcessed = 0;
// Data Integrity Check
//
ASSERT( _CrtIsValidPointer((const void *)lpData, nDataSize, FALSE) );
{
// Data is valid - Start processing
//
do
{
if (STATE_RECORD_INCOMPLETE == m_nState)
{
nFields = m_nCurrField;
nFieldSize = m_nCurrFieldSize;
}
for(;nParsePos < nDataSize; nParsePos++)
{
DeclarePerfTimer("CStatChanRecordProcessor");
MSG msg;
while(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
PerfTimerReset();
if (lpData[nParsePos] == EOC)
{
// End of field
//
if (nParsePos > 0 && (lpData[nParsePos-1] != EOC))
{
// TODO ASSERT(nFields <= StationRec_Fields);
m_szValidField[nFieldSize] = '\0';
m_cmRecordMap[nFields] = m_szValidField;
nFieldSize = 0;
}
else
{
//nFieldDataPos = nParsePos;
nFieldSize = 0;
m_nCurrFieldSize = 0;
}
nFields++;
m_nCurrField++;
}
else if (lpData[nParsePos] == EOR)
{
// End of the record
//
DeclarePerfTimer("CStatChanRecordProcessor");
PerfTimerReset();
if (UPDATE_SUCCEEDED != m_UpdateDatabase(m_cmRecordMap))
{
if (STATE_RECORD_ERROR == m_nState)
{
m_nState = STATE_RECORDS_FAIL;
return m_nState;
}
else
m_nState = STATE_RECORD_ERROR;
}
PerfTimerDump("m_UpdateDatabase");
m_cmRecordMap.RemoveAll();
m_nCurrField = nFields = 0;
m_nCurrFieldSize = nFieldSize = 0;
continue;
}
else if (lpData[nParsePos] == EOT)
{
// End of the table
//
m_nState = STATE_RECORDS_PROCESSED;
nParsePos += 2*sizeof(TCHAR);
break;
}
else
{
// Valid field data
//
m_szValidField[nFieldSize] = lpData[nParsePos];
nFieldSize++;
m_nCurrFieldSize++;
}
PerfTimerDump("for loop");
}
} while ((nParsePos < nDataSize) && (m_nState != STATE_RECORDS_PROCESSED));
*pBytesProcessed = nParsePos;
if (m_nState != STATE_RECORDS_PROCESSED)
{
if (lpData[--nParsePos] == EOR)
{
// More records
//
m_nState = STATE_RECORDS_INCOMPLETE;
}
else
{
// record incomplete
//
m_nState = STATE_RECORD_INCOMPLETE;
}
}
}
}
return m_nState;
}
/////////////////////////////////////////////////////////////////////////
//
// METHOD: m_UpdateDatabase
//
// PARAMETERS: [IN] cmStationRecord - map containing record fields
//
// PURPOSE: Updates the Guide Store
//
/////////////////////////////////////////////////////////////////////////
//
int CStatChanRecordProcessor::m_UpdateDatabase(CRecordMap& cmRecord)
{
int iRet = ERROR_UPDATE;
CString csName, csCallLetters, csNetwork;
CString csStationNumStr, csChannelNumStr;
CWtmsloadApp* ctmsLoapApp = (CWtmsloadApp*) AfxGetApp();
TCHAR ConvBuffer[20] = {0};
IServicePtr pTMSService = NULL;
IChannelPtr pTMSChannel = NULL;
IChannelPtr pTMSChannelMatch = NULL;
// Lookup the Name entry in the StationRecord Map
//
cmRecord.Lookup(StatChanRec_Name, csName);
csName = csName.Left(ssfStatChanFieldInfo[StatChanRec_Name].nWidth);
csName.TrimLeft();
csName.TrimRight();
// Lookup the Number entry in the StationRecord Map
//
cmRecord.Lookup(StatChanRec_Num, csStationNumStr);
csStationNumStr.TrimLeft();
csStationNumStr.TrimRight();
// Lookup the Call Letters entry in the StationRecord Map
//
cmRecord.Lookup(StatChanRec_CallLetters, csCallLetters);
csCallLetters = csCallLetters.Left(4);
csCallLetters.MakeUpper();
// Lookup the Network entry in the StationRecord Map
//
cmRecord.Lookup(StatChanRec_NetworkID, csNetwork);
csNetwork.TrimLeft();
csNetwork.TrimRight();
// Lookup the Channel Number
//
cmRecord.Lookup(StatChanRec_ChannelNumber, csChannelNumStr);
csChannelNumStr.TrimLeft();
csChannelNumStr.TrimRight();
// A new service will be added if the Service is for a Channel that does not already
// have the "ServiceID" associated with it
//
pTMSChannelMatch = ctmsLoapApp->m_pgsChannels.FindChannelMatch(
csChannelNumStr.GetBuffer(ssfStatChanFieldInfo[StatChanRec_ChannelNumber].nWidth),
csStationNumStr.GetBuffer(ssfStatChanFieldInfo[StatChanRec_Num].nWidth));
if (NULL != pTMSChannelMatch)
{
// Add the "channel + service" data for use by ScheduleEntries
//
IServicePtr pServiceMatch = NULL;
pServiceMatch = pTMSChannelMatch->GetService();
m_ChannelIDMap[csChannelNumStr.GetBuffer(ssfStatChanFieldInfo[StatChanRec_ChannelNumber].nWidth)]
= _ltot(pServiceMatch->GetID(), ConvBuffer, 10);
// Get the corresponding service ID
//
CString csChannelID(_ltot(pServiceMatch->GetID(), ConvBuffer, 10));
// The hash table key is based on StationNum and ChannelNum
//
CString csStatChan = csStationNumStr + "," + csChannelNumStr;
// Make the corresponding Hash table entry
//
m_ChannelIDMap.SetAt(csStatChan, csChannelID); // TODO: Add exception handling
#ifdef _DUMP_LOADER
wsprintf(szDiagBuff, "Saving #%d Channel ID for %s : %d\r\n", ChannelCnt, csStatChan, cct.ChannelID());
if (NULL != hDiagFile)
{
::WriteFile(hDiagFile, szDiagBuff, lstrlen(szDiagBuff), &dwBytesWritten, 0);
}
#endif
iRet = UPDATE_SUCCEEDED;
}
else
{
ITuningSpace* pTuningSpace = ctmsLoapApp->m_pgsChannelLineup.GetTuningSpace();
if (NULL != pTuningSpace)
{
ITuneRequest* pTuneRequest = NULL;
// Create an empty tune request
//
pTuningSpace->CreateTuneRequest(&pTuneRequest);
if (NULL != pTuneRequest)
{
IChannelTuneRequest* pChannelTuneRequest = NULL;
// Get a specialized tune request for Analog TV
//
pTuneRequest->QueryInterface(__uuidof(IChannelTuneRequest),
reinterpret_cast<void**>(&pChannelTuneRequest));
if (NULL != pChannelTuneRequest)
{
// Set the Channel number
//
pChannelTuneRequest->put_Channel(_ttoi(csChannelNumStr));
// Make the new service entry
//
pTMSService = ctmsLoapApp->m_pgsServices.AddService(pTuneRequest,
csCallLetters.GetBuffer(ssfStatChanFieldInfo[StatChanRec_CallLetters].nWidth),
csStationNumStr.GetBuffer(ssfStatChanFieldInfo[StatChanRec_Num].nWidth),
csName.GetBuffer(ssfStatChanFieldInfo[StatChanRec_Name].nWidth),
csNetwork.GetBuffer(ssfStatChanFieldInfo[StatChanRec_NetworkID].nWidth),
0,
0);
}
}
}
#ifdef _DUMP_LOADER
ChannelCnt++;
#endif
long lChannelNumber = _ttol(csChannelNumStr);
if (NULL != pTMSService)
{
// Add the channel
//
pTMSChannel = ctmsLoapApp->m_pgsChannels.AddChannel(pTMSService,
csStationNumStr.GetBuffer(ssfStatChanFieldInfo[StatChanRec_Num].nWidth),
csChannelNumStr.GetBuffer(ssfStatChanFieldInfo[StatChanRec_ChannelNumber].nWidth),
lChannelNumber);
}
else
return ERROR_UPDATE_ADD;
if (NULL != pTMSChannel)
{
// Add the "channel + service" data for use by ScheduleEntries
//
m_ChannelIDMap[csChannelNumStr.GetBuffer(ssfStatChanFieldInfo[StatChanRec_ChannelNumber].nWidth)] =
_ltot(pTMSService->GetID(), ConvBuffer, 10);
CString csChannelID(_ltot(pTMSService->GetID(), ConvBuffer, 10));
CString csStatChan = csStationNumStr + "," + csChannelNumStr;
// Make the corresponding Hash table entry
//
m_ChannelIDMap.SetAt(csStatChan, csChannelID);
#ifdef _DUMP_LOADER
wsprintf(szDiagBuff, "Saving #%d Channel ID for %s : %d\r\n", ChannelCnt, csStatChan, cct.ChannelID());
if (NULL != hDiagFile)
{
::WriteFile(hDiagFile, szDiagBuff, lstrlen(szDiagBuff), &dwBytesWritten, 0);
}
#endif
iRet = UPDATE_SUCCEEDED;
}
else
return ERROR_UPDATE_ADD;
}
return iRet;
}
long CStatChanRecordProcessor::m_GetChannelID(LPCTSTR lpChannelNum)
{
CString csChannelID;
m_ChannelIDMap.Lookup(lpChannelNum, csChannelID);
return _ttol(csChannelID);
}
int CStatChanRecordProcessor::m_GetState()
{
return m_nState;
}
int CStatChanRecordProcessor::m_GetError()
{
return m_nError;
}
int CStatChanRecordProcessor::m_GetErrorString(CString& csErrStr)
{
if (m_nError)
{
// If there is an error to return
//
return csErrStr.LoadString(m_nError);
}
return FALSE;
}