/******************************************************\ This file implement the class that will parse an inf file. \******************************************************/ #include "inf.h" #define MAX_INF_STR 8192*2 #define LanguageSection "[LanguagesSupported]" #define LanguageSection1 "[LanguageID]" // Constructors and Destructors CInfFile::CInfFile() { m_lBufSize = -1; m_pfileStart = NULL; m_pfilePos = NULL; m_pfileLastPos = NULL; m_pfileLocalize = NULL; m_strLang = "0000000000"; } CInfFile::CInfFile(LPCTSTR strFileName ) { CFileException fe; Open(strFileName, CFile::modeRead | CFile::shareDenyWrite, &fe); } CInfFile::~CInfFile() { if(m_pfileStart) { m_file.Close(); delete m_pfileStart; } } ////////////////////////////////////////////////////////////////////////////////////////// // String functions BOOL CInfFile::ReadString(CString & str, BOOL bLastFilePos) { if(m_pfilePos==NULL) return FALSE; // search for the next /n in the file BYTE * pEnd = (BYTE*)memchr(m_pfilePos, '\n', (size_t)(m_lBufSize-(m_pfilePos-m_pfileStart))); if(!pEnd) return FALSE; if(bLastFilePos) m_pfileLastPos = m_pfilePos; int istrSize = (int)((pEnd-m_pfilePos) > MAX_INF_STR ? MAX_INF_STR : (pEnd-m_pfilePos)); LPSTR pStr = (LPSTR)str.GetBuffer(istrSize); memcpy(pStr, m_pfilePos, istrSize-1); if(*(pEnd-1)=='\r') *(pStr+istrSize-1) = '\0'; else *(pStr+istrSize) = '\0'; m_pfilePos = pEnd+1; str.ReleaseBuffer(); return TRUE; } BOOL CInfFile::ReadSectionString(CString & str, BOOL bRecursive) { CString strNext; BYTE * pPos = m_pfilePos; while(ReadString(strNext, !bRecursive)) { if(!strNext.IsEmpty()) { if(!bRecursive) str = ""; // Check for a section if(strNext.Find('[')!=-1 && strNext.Find(']')!=-1) break; // remove spaces at the end of the string... strNext.TrimRight(); // // Check for multiple line. Assume only last char can be a + // if(strNext.GetAt(strNext.GetLength()-1)=='+') { // // Remove the + // if(!str.IsEmpty()) { strNext.TrimLeft(); //strNext = strNext.Mid(1); } str += strNext.Left(strNext.GetLength()-1); ReadSectionString(str, TRUE); } else { if(!str.IsEmpty()) { strNext.TrimLeft(); } str += strNext; } // // Make sure the " are balanced with // int iPos; while((iPos = str.Find("\"\""))!=-1) { str = str.Left(iPos) + str.Mid(iPos+2); } return TRUE; } } m_pfilePos = pPos; return FALSE; } BOOL CInfFile::ReadSectionString(CInfLine & str) { CString strLine; if( !ReadSectionString(strLine) ) return FALSE; str = strLine; return TRUE; } BOOL CInfFile::ReadTextSection(CString & str) { CString strSection; while(ReadSection(strSection)) { if(strSection.Find(m_strLang)!=-1) { str = strSection; return TRUE; } } return FALSE; } BOOL CInfFile::ReadSection(CString & str) { if(m_pfilePos==NULL) return 0; BYTE * pOpen; BYTE * pClose; BYTE * pEnd; BOOL bFound = FALSE; while(!bFound) { // search for the next [ in the file if((pOpen = (BYTE*)memchr(m_pfilePos, '[', (size_t)(m_lBufSize-(m_pfilePos-m_pfileStart))))==NULL) return 0; if((pClose = (BYTE*)memchr(pOpen, ']', (size_t)(m_lBufSize-(pOpen-m_pfileStart))))==NULL) return 0; if((pEnd = (BYTE*)memchr(pOpen, '\n', (size_t)(m_lBufSize-(pOpen-m_pfileStart))))==NULL) return 0; // pClose must be before pEnd if((pClose>pEnd) || (*(pOpen-1)!='\n') || (*(pClose+1)!='\r')) m_pfilePos = pEnd+1; else bFound = TRUE; } int istrSize = (int)((pEnd-pOpen) > MAX_INF_STR ? MAX_INF_STR : (pEnd-pOpen)); LPSTR pStr = (LPSTR)str.GetBuffer(istrSize); memcpy(pStr, pOpen, istrSize-1); if(*(pEnd-1)=='\r') *(pStr+istrSize-1) = '\0'; else *(pStr+istrSize) = '\0'; m_pfilePos = pEnd+1; str.ReleaseBuffer(); return 1; } ////////////////////////////////////////////////////////////////////////////////////////// // File functions LONG CInfFile::Seek( LONG lOff, UINT nFrom ) { switch(nFrom) { case SEEK_SET: if(lOff<=m_lBufSize) m_pfilePos = m_pfileStart+lOff; else return -1; break; case SEEK_CUR: if(lOff<=m_lBufSize-(m_pfilePos-m_pfileStart)) m_pfilePos = m_pfilePos+lOff; else return -1; break; case SEEK_END: if(lOff<=m_lBufSize) m_pfilePos = m_pfileStart+(m_lBufSize-lOff); else return -1; break; case SEEK_LOC: if(m_pfileLocalize) m_pfilePos = m_pfileLocalize; else return -1; break; default: break; } return ((LONG)(m_pfilePos-m_pfileStart)); } BOOL CInfFile::Open( LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError ) { CFileException fe; if(!pError) pError = &fe; if(!m_file.Open(lpszFileName, nOpenFlags, pError)) { AfxThrowFileException(pError->m_cause, pError->m_lOsError); return FALSE; } m_lBufSize = m_file.GetLength()+1; m_pfileStart = new BYTE[m_lBufSize]; if(m_pfileStart==NULL) { AfxThrowMemoryException(); return FALSE; } m_pfileLastPos = m_pfilePos = m_pfileStart; m_file.Read(m_pfileStart, m_lBufSize ); *(m_pfilePos+m_lBufSize) = '\0'; // find the localization section /*************************************************************************************\ I'm assuming there are no other \0 in the buffer other than the one I've just placed. This is a fair assumption since this is a text file and not a binary file. I can then use strstr to get to the first occurrence, if any of the localization string section and place my current position buffer there. \*************************************************************************************/ m_pfileLocalize = m_pfilePos = (BYTE*)strstr((LPSTR)m_pfileStart, LanguageSection); // // Check if we have the other language ID tag // if(!m_pfileLocalize) m_pfileLocalize = m_pfilePos = (BYTE*)strstr((LPSTR)m_pfileStart, LanguageSection1); // Get the language if(m_pfileLocalize) { BYTE * pStr = ((BYTE*)memchr(m_pfileLocalize, '\n', (size_t)(m_lBufSize-(m_pfileLocalize-m_pfileStart)))+1); BYTE * pEnd = ((BYTE*)memchr(pStr, '\n', (size_t)(m_lBufSize-(pStr-m_pfileStart)))-1); TRACE("CInfFile::Open =====> pStr = 0X%X, pEnd = 0X%X\n", pStr, pEnd); m_strLang = ""; while( pStr pStr = %c, 0X%X\n", *pStr, pStr); if( isalpha(*pStr++) ) m_strLang += *(pStr-1); } } return TRUE; } ////////////////////////////////////////////////////////////////////////////////////////// // Buffer functions const BYTE * CInfFile::GetBuffer(LONG lPos /* = 0 */) { if(lPos>m_lBufSize || lPos<0) return NULL; return( (const BYTE *)(m_pfileStart+lPos) ); } /******************************************************************************************\ CInfLine This class will parse the line and separate tag and text \******************************************************************************************/ CInfLine::CInfLine() { m_strData = ""; m_strTag = ""; m_strText = ""; m_bMultipleLine = FALSE; } CInfLine::CInfLine( LPCSTR lpStr ) { m_bMultipleLine = FALSE; m_strData = lpStr; SetTag(); SetText(); } void CInfLine::SetTag() { m_strTag = ""; // find the = in m_strData int iPos = m_strData.Find('='); if(iPos==-1) return; m_strTag = Clean(m_strData.Left( iPos )); m_strTag.TrimRight(); m_strTag.TrimLeft(); } void CInfLine::SetText() { m_strText = ""; // find the = in m_strData int iPos = m_strData.Find('='); if(iPos==-1) return; m_strText = Clean(m_strData.Right( m_strData.GetLength()-iPos-1 )); m_strText = m_strData.Right( m_strData.GetLength()-iPos-1 ); } void CInfLine::ChangeText(LPCSTR str) { m_strText = str; // find the = in m_strData int iPos = m_strData.Find('='); if(iPos==-1) return; m_strData = m_strData.Left( iPos+1 ); m_strData += m_strText; } ////////////////////////////////////////////////////////////////////////////////////////// // copy operators CInfLine& CInfLine::operator=(const CInfLine& infstringSrc) { m_strData = infstringSrc.m_strData; m_strTag = infstringSrc.m_strTag; m_strText = infstringSrc.m_strText; m_bMultipleLine = infstringSrc.m_bMultipleLine; return *this; } CInfLine& CInfLine::operator=(LPCTSTR lpsz) { m_bMultipleLine = FALSE; m_strData = lpsz; SetTag(); SetText(); return *this; } ////////////////////////////////////////////////////////////////////////////////////////// // support functions CString CInfLine::Clean(LPCSTR lpstr) { CString str = lpstr; int iPos = str.Find('"'); if(iPos!=-1) { str = str.Right( str.GetLength()-iPos-1 ); iPos = str.ReverseFind('"'); if(iPos!=-1) { str = str.Left( iPos ); } } return str; }