bool Get_XML_colour (CXMLelement & node, const char * sName, COLORREF & cValue, const bool bUseDefault) { CString strValue; if (!Get_XML_string (node, sName, strValue, true, true)) if (bUseDefault) return false; else { cValue = 0; // default is black return false; } if (strValue.IsEmpty ()) ThrowErrorException ("No colour supplied for attribute named '%s'" , sName); if (SetColour (strValue, cValue)) ThrowErrorException ("Invalid colour code \"%s\" for attribute named '%s'" , (LPCTSTR) strValue, sName); return true; } // end of Get_XML_colour
void CXMLparser::ProcessEntity (void) { CString strName; CString strValue; CString strTemp; strName = GetName ("entity"); strTemp = strName.Left (3); strTemp.MakeUpper (); if (strTemp == "XML") ThrowErrorException ("Names starting with \"XML\" are reserved"); strValue = GetValue ("entity", strName); // entities might have entities in them, so replace them m_CustomEntityMap.SetAt (strName, ReplaceEntities (strValue)); if (m_xmlBuff [m_xmlPos] != '>') ThrowErrorException ("Expected '>', got %c", m_xmlBuff [m_xmlPos]); m_xmlPos++; // skip > // bypass spaces and comments SkipComments (true); } // end of CXMLparser::ProcessEntity
t_regexp * regcomp(const char *exp, const int options) { const char *error; int erroroffset; t_regexp * re; pcre * program; pcre_extra * extra; program = pcre_compile(exp, options, &error, &erroroffset, NULL); if (!program) ThrowErrorException("Failed: %s at offset %d", Translate (error), erroroffset); // study it for speed purposes extra = pcre_study(program, 0, &error); if (error) { pcre_free (program); ThrowErrorException("Regexp study failed: %s", error); } // we need to allocate memory for the substring offsets re = new t_regexp; // remember program and extra stuff re->m_program = program; re->m_extra = extra; re->m_iExecutionError = 0; // no error now return re; }
void CXMLparser::SkipComments (const bool bAndSpaces) { while (true) // loop in case consecutive comments, or comment - space - comment { if (bAndSpaces) SkipSpaces (); // comment? if (m_xmlBuff [m_xmlPos] == '<' && m_xmlBuff [m_xmlPos + 1] == '!' && m_xmlBuff [m_xmlPos + 2] == '-' && m_xmlBuff [m_xmlPos + 3] == '-') { // skip comment m_xmlPos += 4; // skip <!-- while (m_xmlBuff [m_xmlPos] != '-' || m_xmlBuff [m_xmlPos + 1] != '-' || m_xmlBuff [m_xmlPos + 2] != '>') { if (m_xmlBuff [m_xmlPos] == 0) ThrowErrorException ("Unterminated comment at end of file"); if (m_xmlBuff [m_xmlPos] == '-' && m_xmlBuff [m_xmlPos + 1] == '-') ThrowErrorException ("Invalid '--' inside comment"); if (m_xmlBuff [m_xmlPos] == '\n') m_xmlLine++; // count lines m_xmlPos++; } // here for end of comment m_xmlPos += 3; // skip --> } // end of comment else return; // no comment, all done }; } // end of SkipComments
void CXMLparser::ProcessDoctype (void) { m_strDocumentName = GetName ("Root document"); // document name may be followed by SYSTEM or PUBLIC if (isalpha (m_xmlBuff [m_xmlPos])) { CString strName = GetName ("External ID"); // we'll get and ignore these for future compatibility if (strName == "SYSTEM") GetValue ("SYSTEM", "DTD name"); // eg. SYSTEM "c:\blah\my.dtd" else if (strName == "PUBLIC") { GetValue ("PUBLIC", "Public ID"); // eg. PUBLIC "blah" "c:\blah\my.dtd" GetValue ("PUBLIC", "DTD name"); } else ThrowErrorException ("Unsupported declaration \"%s\" inside <!DOCTYPE ...>", (LPCTSTR) strName); } // end of SYSTEM/PUBLIC if (m_xmlBuff [m_xmlPos] == '[') ProcessDTD (); if (m_xmlBuff [m_xmlPos] != '>') { // shouldn't have end-of-file before the > if (m_xmlBuff [m_xmlPos] == 0) ThrowErrorException ("Unexpected end-of-file inside <!DOCTYPE> declaration"); ThrowErrorException ("Unsupported declaration inside <!DOCTYPE ...>"); } // end of looking for attributes m_xmlPos++; // skip '>' symbol } // end of CXMLparser::ProcessDoctype
void CXMLparser::ProcessDeclaration (const CString strDeclaration) { if (strDeclaration == "DOCTYPE") ProcessDoctype (); else ThrowErrorException ("Unrecognised declaration: <!%s ...>", (LPCTSTR) strDeclaration); } // end of CXMLparser::ProcessDeclaration
CString CXMLparser::ReplaceEntities (const CString strSource) { // look for entities imbedded in the string const char * p = strSource; const char * pStart = strSource; // where buffer starts const char * pEntity; CString strFixedValue; CString strEntity; long length; // quick check to eliminate ones that don't have imbedded entities if (strSource.Find ('&') == -1) return strSource; strFixedValue.Empty (); for ( ; *p; p++) { if (*p == '&') { // copy up to ampersand length = p - pStart; if (length > 0) strFixedValue += CString (pStart, length); p++; // skip ampersand pEntity = p; // where entity starts if (*p == '#') p++; while (isalnum (*p) || *p == '-' || *p == '.' || *p == '_') p++; if (*p != ';') ThrowErrorException ("No closing \";\" in XML entity argument \"&%s\"", (LPCTSTR) CString (pEntity, p - pEntity)); strFixedValue += Get_XML_Entity (CString (pEntity, p - pEntity)); // add to list pStart = p + 1; // move on past the entity } // end of having an ampersand } // end of processing the value // copy last bit strFixedValue += pStart; return strFixedValue; } // end of CXMLparser::ReplaceEntities
void CXMLparser::ProcessDTD (void) { CString strName; m_xmlPos++; // skip the [ symbol SkipComments (true); while (m_xmlBuff [m_xmlPos] != ']') { // shouldn't have end-of-file before the > if (m_xmlBuff [m_xmlPos] == 0) ThrowErrorException ("Unexpected end-of-file inside DTD declaration"); // look for declaration start if (m_xmlBuff [m_xmlPos] != '<' || m_xmlBuff [m_xmlPos + 1] != '!') ThrowErrorException ("Expected '<!', got %c", m_xmlBuff [m_xmlPos]); m_xmlPos += 2; // skip <! strName = GetName ("DTD Declaration"); // we only support <!ENTITY ... > right now if (strName == "ENTITY") ProcessEntity (); else ThrowErrorException ("Unsupported declaration <!%s ...>", (LPCTSTR) strName); } // end of looking for declarations m_xmlPos++; // skip ']' symbol SkipComments (true); } // end of CXMLparser::ProcessDTD
bool Get_XML_boolean (CXMLelement & node, const char * sName, bool & bValue, const bool bUseDefault) { CString strValue; if (!Get_XML_string (node, sName, strValue, bUseDefault)) if (bUseDefault) return false; // be nice and let them slip in Y or y strValue.MakeLower (); if (strValue == "0" || strValue == "" || // empty can be considered false strValue == "no" || strValue == "n" || strValue == "false" || strValue == "f" ) { bValue = false; return true; } if (strValue == "1" || strValue == "-1" || strValue == "yes" || strValue == "y" || strValue == "true" || strValue == "t" ) { bValue = true; return true; } ThrowErrorException ("Boolean attribute named \"%s\" has unrecognised value \"%s\"", sName, (LPCTSTR) strValue); bValue = false; return true; } // end of Get_XML_boolean
/////////////////////////////////////////////////////////////////////////////// // Write to a file. An assertion will occur if file was opened for reading. // Inputs: // unsigned int size Number of bytes to write to the file. // const char* bufferToWrite Buffer containing data to write to the file. // Exceptions: // ErrorException thrown on failure. /////////////////////////////////////////////////////////////////////////////// void RawFileLinux::Write( unsigned int size, const char* bufferToWrite ) { //Write everything in one pass assert( IsOpen() ); filestream.exceptions( std::fstream::badbit | std::fstream::failbit | std::fstream::goodbit ); try { filestream.write( bufferToWrite, size ); lastPosition = position; position = filestream.tellp(); filestream.clear(); } catch( std::fstream::failure e ) { //throw exception ThrowErrorException( e ); } }
bool Get_XML_number (CXMLelement & node, const char * sName, long & iValue, const bool bUseDefault, long iMinimum, long iMaximum) { CString strValue; if (!Get_XML_string (node, sName, strValue, bUseDefault)) if (bUseDefault) return false; else strValue = "0"; // default is zero __int64 iResult = 0; const char * p = strValue; bool bNegative = false; // see if sign given if (*p == '-') { bNegative = true; p++; } else if (*p == '+') p++; if (*p == 0) ThrowErrorException ("No number suppied for numeric attribute named '%s'" , sName); if (!isdigit (*p)) ThrowErrorException ("Invalid number \"%s\" for numeric attribute named '%s'" , (LPCTSTR) strValue, sName); for (iResult = 0; *p; p++) { if (!isdigit (*p)) ThrowErrorException ("Invalid character '%c' in numeric attribute named '%s'" , *p, sName); iResult *= 10; iResult += *p - '0'; if (iResult > ((__int64) LONG_MAX + 1)) // to allow for LONG_MIN which will be one more ThrowErrorException ("Value '%s' too large in numeric attribute named '%s'" , (LPCTSTR) strValue, sName); } // make negative if necessary if (bNegative) iResult = 0 - iResult; // fix up default 0, 0 to be 0, 1 if (iMinimum == 0 && iMaximum == 0) iMaximum = 1; if (iResult > iMaximum) ThrowErrorException ("Value '%s' too large in numeric attribute named '%s'. " "Range is %ld to %ld.", (LPCTSTR) strValue, sName, iMinimum, iMaximum); if (iResult < iMinimum) ThrowErrorException ("Value '%s' too small in numeric attribute named '%s'. " "Range is %ld to %ld.", (LPCTSTR) strValue, sName, iMinimum, iMaximum); iValue = (long) iResult; return true; } // end of Get_XML_number
CString CXMLparser::GetValue (const char * sType, const char * sName) { char cQuote; UINT iStart; CString strValue; int iContentLen; // in case spaces before the value SkipSpaces (); // find what sort of quote they are using cQuote = m_xmlBuff [m_xmlPos]; if (cQuote == 0) ThrowErrorException ("Unexpected end-of-file looking for value of %s named %s", sType, sName); if (cQuote != '\'' && cQuote != '\"') // value starting with > is really an omitted value if (cQuote == '>') ThrowErrorException ("Value for %s not supplied", sType); // detect a comment here as a special case else if (m_xmlBuff [m_xmlPos] == '<' && m_xmlBuff [m_xmlPos + 1] == '!' && m_xmlBuff [m_xmlPos + 2] == '-' && m_xmlBuff [m_xmlPos + 3] == '-') ThrowErrorException ("Comment not valid here"); else ThrowErrorException ("Value for %s named '%s' not supplied (in quotes)", sType, sName); m_xmlPos++; // get past quote iStart = m_xmlPos; // start of value while (m_xmlBuff [m_xmlPos] != cQuote) { if (m_xmlBuff [m_xmlPos] == '\n' || m_xmlBuff [m_xmlPos] == '\r' || m_xmlBuff [m_xmlPos] == 0) ThrowErrorException ("Value for %s named '%s' not terminated (no closing quote)", sType, sName); // <![CDATA[ terminator invalid here (ie. ]]> ) if (m_xmlBuff [m_xmlPos] == ']' && m_xmlBuff [m_xmlPos + 1] == ']' && m_xmlBuff [m_xmlPos + 2] == '>') ThrowErrorException ("Value for %s named '%s' may not contain CDATA terminator: ']]>'", sType, sName); // don't let them slip in non-printables if ((unsigned char) m_xmlBuff [m_xmlPos] < ' ') ThrowErrorException ("Non-printable character, code %i, not permitted for " "value for %s named '%s'", (int) m_xmlBuff [m_xmlPos], sType, sName); m_xmlPos++; } iContentLen = m_xmlPos - iStart; m_xmlPos++; // get past quote SkipSpaces (); // construct value from buffer return CString (&m_xmlBuff [iStart], iContentLen); } // end of CXMLparser::GetValue
bool Get_XML_date (CXMLelement & node, const char * sName, CTime & tValue, const bool bUseDefault) { CString strValue; if (!Get_XML_string (node, sName, strValue, true, true)) if (bUseDefault) return false; else { tValue = 0; // default is no time return false; } if (strValue.IsEmpty ()) ThrowErrorException ("No time supplied for attribute named '%s'" , sName); // break up date into date portion / time portion CStringList strDateTime; StringToList (strValue, " ", strDateTime); if (strDateTime.GetCount () < 1 || strDateTime.GetCount () > 2) ThrowErrorException ("Date/time must consist of YYYY-MM-DD [ HH:MM:SS ]"); CString strDate = strDateTime.RemoveHead (); CString strTime; if (!strDateTime.IsEmpty ()) strTime = strDateTime.RemoveHead (); CString strYear, strMonth, strDay; CStringList strDateList; StringToList (strDate, "-", strDateList); if (strDateList.GetCount () != 3) ThrowErrorException ("Date must consist of YYYY-MM-DD"); strYear = strDateList.RemoveHead (); strMonth = strDateList.RemoveHead (); strDay = strDateList.RemoveHead (); if (!IsNumber (strYear)) ThrowErrorException ("Year is not numeric"); if (!IsNumber (strMonth)) ThrowErrorException ("Month is not numeric"); if (!IsNumber (strDay)) ThrowErrorException ("Day is not numeric"); int iYear, iMonth, iDay; iYear = atoi (strYear); iMonth = atoi (strMonth); iDay = atoi (strDay); if (iYear < 1900 || iYear > 2100) ThrowErrorException ("Year must be in range 1900 to 2100"); if (iMonth < 1 || iMonth > 12) ThrowErrorException ("Month must be in range 1 to 12"); if (iDay < 1 || iDay > 31) ThrowErrorException ("Month must be in range 1 to 31"); int iHour = 0, iMinute = 0, iSecond = 0; if (!strTime.IsEmpty ()) { CString strHour, strMinute, strSecond; CStringList strTimeList; StringToList (strTime, ":", strTimeList); if (strTimeList.GetCount () > 3) ThrowErrorException ("Time must consist of HH, HH:MM, or HH:MM:SS"); strHour = strTimeList.RemoveHead (); strMinute = "0"; strSecond = "0"; if (!strTimeList.IsEmpty ()) { strMinute = strTimeList.RemoveHead (); if (!strTimeList.IsEmpty ()) strSecond = strTimeList.RemoveHead (); } if (!IsNumber (strHour)) ThrowErrorException ("Hour is not numeric"); if (!IsNumber (strMinute)) ThrowErrorException ("Minute is not numeric"); if (!IsNumber (strSecond)) ThrowErrorException ("Second is not numeric"); iHour = atoi (strHour); iMinute = atoi (strMinute); iSecond = atoi (strSecond); if (iHour < 0 || iHour > 23) ThrowErrorException ("Hour must be in range 0 to 23"); if (iMinute < 0 || iMinute > 59) ThrowErrorException ("Minute must be in range 0 to 59"); if (iSecond < 0 || iSecond > 59) ThrowErrorException ("Minute must be in range 0 to 59"); } // end of having a time tValue = CTime (iYear, iMonth, iDay, iHour, iMinute, iSecond, 0); return true; } // end of Get_XML_date
bool Get_XML_double (CXMLelement & node, const char * sName, double & dValue, const bool bUseDefault, const double dMinimum, const double dMaximum) { CString strValue; if (!Get_XML_string (node, sName, strValue, bUseDefault)) if (bUseDefault) return false; else strValue = "0"; // default is zero double dResult = 0; const char * p = strValue; int iDots = 0; int iExponents = 0; // see if sign given if (*p == '-' || *p == '+') p++; if (*p == 0) ThrowErrorException ("No number suppied for numeric attribute named '%s'" , sName); if (!isdigit (*p)) ThrowErrorException ("Invalid number \"%s\" for numeric attribute named '%s'" , (LPCTSTR) strValue, sName); for ( ; *p; p++) { if (*p == '.') { if (++iDots > 1) ThrowErrorException ("Too many decimal places for numeric attribute named '%s'" , sName); } // end of decimal place else if (toupper (*p) == 'E') { if (++iExponents > 1) ThrowErrorException ("Too many 'E' characters for numeric attribute named '%s'" , sName); // exponent may have sign if (*p == '-' || *p == '+') p++; } // end of exponent else if(!isdigit (*p)) ThrowErrorException ("Invalid character '%c' in numeric attribute named '%s'" , *p, sName); } // end of checking each character myAtoF (strValue, &dResult); /* // myAtoF does not return myAtoF if (dResult == c || dResult == -HUGE_VAL) ThrowErrorException ("Value '%s' out of range in numeric attribute named '%s'" , (LPCTSTR) strValue, sName); */ if (dResult > dMaximum) ThrowErrorException ("Value '%s' too large in numeric attribute named '%s'. " "Range is %g to %g.", (LPCTSTR) strValue, sName, dMinimum, dMaximum); if (dResult < dMinimum) ThrowErrorException ("Value '%s' too small in numeric attribute named '%s'. " "Range is %g to %g.", (LPCTSTR) strValue, sName, dMinimum, dMaximum); dValue = dResult; return true; } // end of Get_XML_double
CString CXMLparser::Get_XML_Entity (CString & strName) { CString strEntityContents; // look for &#nnn; if (strName [0] == '#') { int iResult = 0; // validate and work out number if (strName [1] == 'x') { for (int i = 2; i < strName.GetLength (); i++) { if (!isxdigit (strName [i])) { ThrowErrorException ("Invalid hex number in XML entity: &%s;" , (LPCTSTR) strName); return ""; } int iNewDigit = toupper (strName [i]); if (iNewDigit >= 'A') iNewDigit -= 7; if (iResult & 0xF0) ThrowErrorException ("Invalid hex number in XML entity: &%s; " "- maximum of 2 hex digits", (LPCTSTR) strName); iResult = (iResult << 4) + iNewDigit - '0'; } } // end of hex entity else { for (int i = 1; i < strName.GetLength (); i++) { if (!isdigit (strName [i])) { ThrowErrorException ("Invalid number in XML entity: &%s;" , (LPCTSTR) strName); return ""; } iResult *= 10; iResult += strName [i] - '0'; } } // end of decimal entity if (iResult != 9) // we will accept tabs ;) if (iResult < 32 || // don't allow nonprintable characters iResult > 255) // don't allow characters more than 1 byte { ThrowErrorException ("Disallowed number in XML entity: &%s;" , (LPCTSTR) strName); return ""; } unsigned char cOneCharacterLine [2] = { (unsigned char) iResult, 0}; return (char *) cOneCharacterLine; } // end of entity starting with # // look up global entities first if (App.m_EntityMap.Lookup (strName, strEntityContents)) return strEntityContents; // then try ones for this document else if (m_CustomEntityMap.Lookup (strName, strEntityContents)) return strEntityContents; ThrowErrorException ("Unknown XML entity: &%s;" , (LPCTSTR) strName); return ""; // to avoid warning } // end of CXMLparser::Get_XML_Entity
void CXMLparser::BuildStructure (CFile * file) { m_xmlLength = file->GetLength (); // can hardly be XML if empty file if (m_xmlLength == 0) ThrowErrorException ("Zero length XML file \"%s\"", (LPCTSTR) file->GetFilePath ()); // sanity check - don't read 20 Mb files into memory if (m_xmlLength > MAX_XML_DOCUMENT_SIZE) ThrowErrorException ("XML file \"%s\"too large - maximum permitted is %i bytes", (LPCTSTR) file->GetFilePath (), MAX_XML_DOCUMENT_SIZE); char * p = m_strxmlBuffer.GetBuffer (m_xmlLength + 1); iLineLastItemFound = 0; if (file->Read (p, m_xmlLength) != m_xmlLength) { m_strxmlBuffer.ReleaseBuffer (0); ThrowErrorException ("Could not read XML file"); } m_strxmlBuffer.ReleaseBuffer (m_xmlLength); // look for Unicode (FF FE) if ((unsigned char) m_strxmlBuffer [0] == 0xFF && (unsigned char) m_strxmlBuffer [1] == 0xFE) { CString buf2; const char * q = m_strxmlBuffer; q += 2; // skip indicator bytes // find required buffer length int length = WideCharToMultiByte (CP_UTF8, 0, (LPCWSTR) q, (m_xmlLength - 2) / 2, NULL, 0, NULL, NULL); // make a new string with enough length to hold it char * p = buf2.GetBuffer (length); // convert it WideCharToMultiByte (CP_UTF8, 0, (LPCWSTR) q, (m_xmlLength - 2) / 2, p, length, NULL, NULL); buf2.ReleaseBuffer (length); // copy to our buffer m_strxmlBuffer = buf2; } else // look for UTF-8 indicator bytes (EF BB BF) if ((unsigned char) m_strxmlBuffer [0] == 0xEF && (unsigned char) m_strxmlBuffer [1] == 0xBB && (unsigned char) m_strxmlBuffer [2] == 0xBF) m_strxmlBuffer = m_strxmlBuffer.Mid (3); // skip them // convert tabs to spaces, we don't want tabs in our data m_strxmlBuffer.Replace ('\t', ' '); SeeIfBase64 (m_strxmlBuffer); m_xmlBuff = m_strxmlBuffer; // get const char * pointer to buffer ProcessNode (m_xmlRoot); // process root node } // end of CXMLparser::BuildStructure
CString CXMLparser::GetName (const char * sType) { int iStart; int iNameLen; iStart = m_xmlPos; // start of name if (m_xmlBuff [m_xmlPos] == 0) ThrowErrorException ("Unexpected end-of-file looking for %s name", sType); // name must start with letter or underscore if (!isalpha (m_xmlBuff [m_xmlPos]) && m_xmlBuff [m_xmlPos] != '_') ThrowErrorException ("%s name must start with letter or underscore, " "but starts with \"%c\"", sType, m_xmlBuff [m_xmlPos]); // build up name while (isalnum (m_xmlBuff [m_xmlPos]) || m_xmlBuff [m_xmlPos] == '-' || m_xmlBuff [m_xmlPos] == '.' || m_xmlBuff [m_xmlPos] == '_') m_xmlPos++; // OK - we now have a name, unless it is empty iNameLen = m_xmlPos - iStart; if (iNameLen == 0) // name starting with > is really an omitted name if (m_xmlBuff [m_xmlPos] == '>') ThrowErrorException ("%s name not supplied", sType); // detect a comment inside an element as a special case else if (m_xmlBuff [m_xmlPos] == '<' && m_xmlBuff [m_xmlPos + 1] == '!' && m_xmlBuff [m_xmlPos + 2] == '-' && m_xmlBuff [m_xmlPos + 3] == '-') ThrowErrorException ("Comment not valid here"); else ThrowErrorException ("%s name cannot start with '%c'", sType, m_xmlBuff [m_xmlPos]); // sanity check - make sure name not ridiculous if (iNameLen > MAX_XML_NAME_LENGTH) ThrowErrorException ("%s name is too long (%i characters) " " maximum permitted is %i characters", sType, iNameLen, MAX_XML_NAME_LENGTH); // in case spaces before next thing SkipSpaces (); // construct name from buffer return CString (&m_xmlBuff [iStart], iNameLen); } // end of CXMLparser::GetName
void CXMLparser::ProcessAttributes (CXMLelement & node) { CAttribute * pAttribute; CString strName; CString strValue; while (m_xmlBuff [m_xmlPos] != '>') { // look for "empty element" terminator: /> if (m_xmlBuff [m_xmlPos] == '/' && m_xmlBuff [m_xmlPos + 1] == '>') { node.bEmpty = true; m_xmlPos++; // skip '/' symbol break; } // look for terminator ?> at end of <?xml tag if (m_xmlBuff [m_xmlPos] == '?' && m_xmlBuff [m_xmlPos + 1] == '>' && node.strName [0] == '?' ) { node.bEmpty = true; m_xmlPos++; // skip '?' symbol break; } // shouldn't have end-of-file before the > if (m_xmlBuff [m_xmlPos] == 0) ThrowErrorException ("Unexpected end-of-file inside element definition for %s", (LPCTSTR) node.strName); // we really should have a name now ... strName = GetName ("Attribute"); // already there? error if (node.AttributeMap.Lookup (strName, pAttribute)) ThrowErrorException ("Duplicate attribute name '%s'", (LPCTSTR) strName); // in case spaces before next thing SkipSpaces (); if (m_xmlBuff [m_xmlPos] != '=') ThrowErrorException ("Attribute name '%s' not followed by '='", (LPCTSTR) strName); m_xmlPos++; // skip the = sign int iLine = m_xmlLine; // line that = sign is on strValue = GetValue ("attribute", strName); pAttribute = new CAttribute; if (!pAttribute) ThrowErrorException ("Could not allocate memory for XML parsing of attribute %s", (LPCTSTR) strName); pAttribute->strName = strName; pAttribute->strValue = ReplaceEntities (strValue); pAttribute->iLine = iLine; // add to map node.AttributeMap.SetAt (strName, pAttribute); } // end of looking for attributes m_xmlPos++; // skip '>' symbol } // end of CXMLparser::ProcessAttributes
void CXMLparser::AssembleContent (CXMLelement & node, const UINT iFirstLine, const UINT iNodeStart) { /* work out content - it will be non-nested text belonging to this element eg. <a>xxx<b>yyy</b>zzz</a> "a" will have content xxxzzz "b" will have content yyy whitespace is preserved You can reassemble an entire element (including nested ones) by concatenating the contents of its children. For cross-platform consistency, carriage returns are dropped, and linefeeds become carriage-return/linefeed */ int iContentLen = m_xmlPos - iNodeStart; int iLines = m_xmlLine - iFirstLine; // lines of content const char * pi = &m_xmlBuff [iNodeStart]; // copy from const char * pl = &m_xmlBuff [m_xmlPos]; // limit of copy char * po = node.strContent.GetBuffer (iContentLen + 1 + iLines); // copy to int iDepth = 0; bool bInside = false; char cQuote = ' '; while (pi < pl) // copy, dropping nested elements { // they might have <blah value=">"> // so we have to skip special characters inside quotes if (bInside && (*pi == '\'' || *pi == '\"')) { cQuote = *pi; // for terminator pi++; while (pi < pl && *pi != cQuote) pi++; pi++; // skip terminating quote continue; // back to start of loop } // end of quotes inside a definition // <![CDATA[ is special - just copy contents if (pi [0] == '<' && pi [1] == '!' && pi [2] == '[' && pi [3] == 'C' && pi [4] == 'D' && pi [5] == 'A' && pi [6] == 'T' && pi [7] == 'A' && pi [8] == '[') { pi += 9; // skip <![CDATA[ // this shouldn't happen if (bInside) ThrowErrorException ("Unexpected '<![CDATA[' inside element definition"); // should be terminated as we checked earlier, but may as well check again while (pi < pl && (pi [0] != ']' || pi [1] != ']' || pi [2] != '>')) { // copy if not nested, and not inside an element definition // -- omit carriage returns if (iDepth == 0 && *pi != '\r') { // make linefeeds into carriage return/linefeed if (*pi == '\n') *po++ = '\r'; // special treatment for ampersands, so they don't get converted // into entities ... if (*pi == '&') *po++ = '\x01'; else *po++ = *pi; // copy it } pi++; } // end of inside <![CDATA[ pi += 3; // skip ]]> continue; // back to start of loop } // end of <![CDATA[ section if (*pi == '<') // going into an element { bInside = true; if (pi [1] == '/') // </tag> drops a level { iDepth--; if (iDepth < 0) iDepth = 0; // cannot have negative depth } else if (pi [1] != '!' && pi [1] != '?') // excepting special ones iDepth++; // <tag> goes up a level } // copy if not nested, and not inside an element definition // -- omit carriage returns if (iDepth == 0 && !bInside && *pi != '\r') { // make linefeeds into carriage return/linefeed if (*pi == '\n') *po++ = '\r'; *po++ = *pi; // copy if not inside an element } // leaving an element (only occurs 'inside' a <... sequence ) if (bInside && pi [0] == '/' && pi [1] == '>') { iDepth--; // cancel level gain - this tag is empty if (iDepth < 0) iDepth = 0; // cannot have negative depth } else if (*pi == '>') // leaving an element bInside = false; pi++; // onto next } *po = 0; // terminating null node.strContent.ReleaseBuffer (-1); // get rid of entities (such as <) in the content node.strContent = ReplaceEntities (node.strContent); // now, in case we had <![CDATA[ sections, replace 0x01 by & node.strContent.Replace ('\x01', '&'); } // end of CXMLparser::AssembleContent
CString CMUSHclientDoc::FixSendText (const CString strSource, const int iSendTo, const t_regexp * regexp, // regular expression (for triggers, aliases) const char * sLanguage, // language for send-to-script const bool bMakeWildcardsLower, const bool bExpandVariables, // convert @foo const bool bExpandWildcards, // convert %x const bool bFixRegexps, // convert \ to \\ for instance const bool bIsRegexp, // true = regexp trigger const bool bThrowExceptions) { CString strOutput; // result of expansion const char * pText, * pStartOfGroup; pText = pStartOfGroup = strSource; while (*pText) { switch (*pText) { /* -------------------------------------------------------------------- * * Variable expansion - @foo becomes <contents of foo> * * -------------------------------------------------------------------- */ case '@': { if (!bExpandVariables) { pText++; // just copy the @ break; } // copy up to the @ sign strOutput += CString (pStartOfGroup, pText - pStartOfGroup); pText++; // skip the @ // @@ becomes @ if (*pText == '@') { pStartOfGroup = ++pText; strOutput += "@"; continue; } const char * pName; bool bEscape = bFixRegexps; // syntax @!variable defeats the escaping if (*pText == '!') { pText++; bEscape = false; } pName = pText; // find end of variable name while (*pText) if (*pText == '_' || isalnum ((unsigned char) *pText)) pText++; else break; /* -------------------------------------------------------------------- * * We have a variable - look it up and do internal replacements * * -------------------------------------------------------------------- */ CString strVariableName (pName, pText - pName); if (strVariableName.IsEmpty ()) { if (bThrowExceptions) ThrowErrorException ("@ must be followed by a variable name"); } // end of no variable name else { CVariable * variable_item; strVariableName.MakeLower (); if (GetVariableMap ().Lookup (strVariableName, variable_item)) { // fix up so regexps don't get confused with [ etc. inside variable CString strVariableContents; if (bEscape) { const char * pi; // allow for doubling in size, plus terminating null char * po = strVariableContents.GetBuffer ((variable_item->strContents.GetLength () * 2) + 1); for (pi = variable_item->strContents; *pi; pi++) { if (((unsigned char) *pi) < ' ') continue; // drop non-printables if (bIsRegexp) if (!isalnum ((unsigned char) *pi) && *pi != ' ') { *po++ = '\\'; // escape it *po++ = *pi; } else *po++ = *pi; // just copy it else // not regexp if (*pi != '*') *po++ = *pi; // copy all except asterisks } *po = 0; // terminating null strVariableContents.ReleaseBuffer (-1); } // end of escaping wanted else strVariableContents = variable_item->strContents; // in the "send" box may need to convert script expansions etc. if (!bFixRegexps) strVariableContents = FixWildcard ((const char *) strVariableContents, false, // not force variables to lowercase iSendTo, sLanguage).c_str (); // fix up HTML sequences if we are sending it to a log file if (m_bLogHTML && iSendTo == eSendToLogFile) strVariableContents = FixHTMLString (strVariableContents); strOutput += strVariableContents; } // end of name existing in variable map else { if (bThrowExceptions) ThrowErrorException ("Variable '%s' is not defined.", (LPCTSTR) strVariableName); } // end of variable does not exist } // end of not empty name // get ready for next batch from beyond the variable pStartOfGroup = pText; } break; // end of '@' /* -------------------------------------------------------------------- * * Wildcard substitution - %1 becomes <contents of wildcard 1> * * - %<foo> becomes <contents of wildcard "foo" * * - %% becomes % * * -------------------------------------------------------------------- */ case '%': if (!bExpandWildcards) { pText++; // just copy the % break; } // see what comes after the % symbol switch (pText [1]) { /* -------------------------------------------------------------------- * * %% * * -------------------------------------------------------------------- */ case '%': // copy up to - and including - the percent sign strOutput += CString (pStartOfGroup, pText - pStartOfGroup + 1); // get ready for next batch from beyond the %% pText += 2; // don't reprocess the %% pStartOfGroup = pText; break; // end of %% /* -------------------------------------------------------------------- * * %0 to %9 * * -------------------------------------------------------------------- */ case '0': // a digit? case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { // copy up to the percent sign strOutput += CString (pStartOfGroup, pText - pStartOfGroup); // output the appropriate replacement text if (regexp) { CString strWildcard = FixWildcard (regexp->GetWildcard (string (1, *++pText)), bMakeWildcardsLower, iSendTo, sLanguage).c_str (); // fix up HTML sequences if we are sending it to a log file if (m_bLogHTML && iSendTo == eSendToLogFile) strWildcard = FixHTMLString (strWildcard); strOutput += strWildcard; } // get ready for next batch from beyond the digit pStartOfGroup = ++pText; } break; // end of %(digit) (eg. %2) /* -------------------------------------------------------------------- * * %<name> * * -------------------------------------------------------------------- */ case '<': { // copy up to the % sign strOutput += CString (pStartOfGroup, pText - pStartOfGroup); pText +=2; // skip the %< const char * pName = pText; // find end of wildcard name while (*pText) if (*pText != '>') pText++; else break; string sWildcardName (pName, pText - pName); if (!sWildcardName.empty () && regexp) { CString strWildcard = FixWildcard (regexp->GetWildcard (sWildcardName), bMakeWildcardsLower, iSendTo, sLanguage).c_str (); // fix up HTML sequences if we are sending it to a log file if (m_bLogHTML && iSendTo == eSendToLogFile) strWildcard = FixHTMLString (strWildcard); strOutput += strWildcard; } // get ready for next batch from beyond the name if (*pText == '>') pText++; pStartOfGroup = pText; } break; // end of %<foo> /* -------------------------------------------------------------------- * * %C - clipboard contents * * -------------------------------------------------------------------- */ case 'C': case 'c': { // copy up to the percent sign strOutput += CString (pStartOfGroup, pText - pStartOfGroup); CString strClipboard; if (GetClipboardContents (strClipboard, m_bUTF_8)) strOutput += strClipboard; else if (bThrowExceptions) ThrowErrorException ("No text on the Clipboard"); // get ready for next batch from beyond the 'c' pText += 2; pStartOfGroup = pText; } break; // end of %c /* -------------------------------------------------------------------- * * %(something else) * * -------------------------------------------------------------------- */ default: pText++; break; } // end of switch on character after '%' break; // end of '%(something)' /* -------------------------------------------------------------------- * * All other characters - just increment pointer so we can copy later * * -------------------------------------------------------------------- */ default: pText++; break; } // end of switch on *pText } // end of not end of string yet // copy last group strOutput += pStartOfGroup; return strOutput; } // end of CMUSHclientDoc::FixSendText
int regexec(register t_regexp *prog, register const char *string, const int start_offset) { int options = App.m_bRegexpMatchEmpty ? 0 : PCRE_NOTEMPTY; // don't match on an empty string int count; // exit if no regexp program to process (possibly because of previous error) if (prog->m_program == NULL) return false; // inspired by a suggestion by Twisol (to remove a hard-coded limit on the number of wildcards) int capturecount = 0; // how many captures did we get? pcre_fullinfo(prog->m_program, NULL, PCRE_INFO_CAPTURECOUNT, &capturecount); // allocate enough memory vector<int> offsets ((capturecount + 1) * 3); // we always get offset 0 - the whole match LARGE_INTEGER start, finish; if (App.m_iCounterFrequency) QueryPerformanceCounter (&start); else { start.QuadPart = 0; finish.QuadPart = 0; } pcre_callout = NULL; count = pcre_exec(prog->m_program, prog->m_extra, string, strlen (string), start_offset, options, &offsets [0], offsets.size ()); if (App.m_iCounterFrequency) { QueryPerformanceCounter (&finish); prog->iTimeTaken += finish.QuadPart - start.QuadPart; } prog->m_iMatchAttempts++; // how many times did we try to match? if (count == PCRE_ERROR_NOMATCH) return false; // no match - don't save matching string etc. // otherwise free program as an indicator that we can't keep trying to do this one if (count <= 0) { pcre_free (prog->m_program); prog->m_program = NULL; pcre_free (prog->m_extra); prog->m_extra = NULL; prog->m_iExecutionError = count; // remember reason ThrowErrorException (TFormat ("Error executing regular expression: %s", (LPCTSTR) Convert_PCRE_Runtime_Error (count))); } // if, and only if, we match, we will save the matching string, the count // and offsets, so we can extract the wildcards later on prog->m_sTarget = string; // for extracting wildcards prog->m_iCount = count; // ditto prog->m_vOffsets.clear (); copy (offsets.begin (), offsets.end (), back_inserter (prog->m_vOffsets)); return true; // match }
void CXMLparser::ProcessNode (CXMLelement & parent) { CString strName; CString strValue; CString strPrefix; UINT iNodeStart = m_xmlPos; UINT iFirstLine = m_xmlLine; while (m_xmlBuff [m_xmlPos]) { // bypass spaces and comments SkipComments (true); // nothing left? all done if (m_xmlBuff [m_xmlPos] == 0) break; // look for element start if (m_xmlBuff [m_xmlPos] != '<') { // not element - must be content // can't have content at root level if (parent.strName.IsEmpty ()) ThrowErrorException ("Expected '<', got \"%c\" (content not permitted here)", m_xmlBuff [m_xmlPos]); if (m_xmlBuff [m_xmlPos] == '\n') m_xmlLine++; // count lines // <![CDATA[ terminator invalid here (ie. ]]> ) if (m_xmlBuff [m_xmlPos] == ']' && m_xmlBuff [m_xmlPos + 1] == ']' && m_xmlBuff [m_xmlPos + 2] == '>') ThrowErrorException ("CDATA terminator ']]>' invalid"); // don't let them slip in non-printables if ((unsigned char) m_xmlBuff [m_xmlPos] < ' ' && (unsigned char) m_xmlBuff [m_xmlPos] != '\n' && (unsigned char) m_xmlBuff [m_xmlPos] != '\r') ThrowErrorException ("Non-printable character, code %i, not permitted", (int) m_xmlBuff [m_xmlPos]); m_xmlPos++; // skip character continue; // keep processing content } m_xmlPos++; // skip < // special cases: <?xml blah?> <!doctype blah> </end-of-something> if (m_xmlBuff [m_xmlPos] == '!' || m_xmlBuff [m_xmlPos] == '?' || m_xmlBuff [m_xmlPos] == '/') { strPrefix = m_xmlBuff [m_xmlPos]; m_xmlPos++; // bypass special types } else strPrefix.Empty (); // special and bizarre case of <![CDATA[ ... ]]> if (strPrefix == '!' && m_xmlBuff [m_xmlPos] == '[' && m_xmlBuff [m_xmlPos + 1] == 'C' && m_xmlBuff [m_xmlPos + 2] == 'D' && m_xmlBuff [m_xmlPos + 3] == 'A' && m_xmlBuff [m_xmlPos + 4] == 'T' && m_xmlBuff [m_xmlPos + 5] == 'A' && m_xmlBuff [m_xmlPos + 6] == '[') { // can't have content at root level if (parent.strName.IsEmpty ()) ThrowErrorException ("<![CDATA[ invalid at root level"); m_xmlPos += 7; // skip [CDATA[ while (m_xmlBuff [m_xmlPos] != ']' || m_xmlBuff [m_xmlPos + 1] != ']' || m_xmlBuff [m_xmlPos + 2] != '>') { // shouldn't have end-of-file before the ]]> if (m_xmlBuff [m_xmlPos] == 0) ThrowErrorException ("Unexpected end-of-file inside [CDATA[ definition"); // don't let them slip in non-printables if ((unsigned char) m_xmlBuff [m_xmlPos] < ' ' && (unsigned char) m_xmlBuff [m_xmlPos] != '\n' && (unsigned char) m_xmlBuff [m_xmlPos] != '\r') ThrowErrorException ("Non-printable character, code %i, not permitted", (int) m_xmlBuff [m_xmlPos]); if (m_xmlBuff [m_xmlPos] == '\n') m_xmlLine++; // count lines m_xmlPos++; // try next character } m_xmlPos += 3; // skip ]]> continue; // back to start of loop } // end of <![CDATA[ section int iLine = m_xmlLine; // line where we expect to see name strName = GetName ("Element"); // check for sequence </blah xxx> if (strPrefix == '/' && m_xmlBuff [m_xmlPos] != '>') if (m_xmlBuff [m_xmlPos] == 0) ThrowErrorException ("Unexpected end-of-file after '</%s'", (LPCTSTR) strName); else ThrowErrorException ("Surplus characters after '</%s'", (LPCTSTR) strName); // check for sequence </blah> if (strPrefix == '/') { if (strName != parent.strName) if (parent.strName.IsEmpty ()) // can't go up a level here :) ThrowErrorException ("Unexpected closing tag </%s> - " "no corresponding opening tag", (LPCTSTR) strName); else ThrowErrorException ("Elements terminated out of sequence, " "expected </%s>, got </%s>", (LPCTSTR) parent.strName, (LPCTSTR) strName); AssembleContent (parent, iFirstLine, iNodeStart); m_xmlPos++; // skip terminating > return; // terminated this node } if (strPrefix == '!') ProcessDeclaration (strName); // process declaration, eg. <!DOCTYPE else { // not a declaration, must be an ordinary element // time to create a new element CXMLelement * pElement = new CXMLelement; if (!pElement) ThrowErrorException ("Could not allocate memory for XML parsing of element %s", (LPCTSTR) strName); // remember its name pElement->strName = strPrefix + strName; pElement->iLine = iLine; parent.ChildrenList.AddTail (pElement); // add to parent's list of children // OK, we have a new sibling for our parent, let's see if it has any attributes ... ProcessAttributes (*pElement); // process its attributes // hmm - we have now got something like <blah> ... // drop down to find children for it - unless 'empty' element if (!pElement->bEmpty) ProcessNode (*pElement); } // end of non-declaration } // end of processing buffer if (!parent.strName.IsEmpty ()) ThrowErrorException ("Unexpected end-of-file while looking for </%s>", (LPCTSTR) parent.strName); } // end of CXMLparser::ProcessNode
static void readfont(CString strName) { #define MAXFIRSTLINELEN 1000 int i,row,numsread; inchr theord; int maxlen,cmtlines,ffright2left; int smush,smush2; char *fileline,magicnum[5]; CStdioFile fontfile (strName, CFile::modeRead|CFile::shareDenyNone|CFile::typeText); readmagic(fontfile,magicnum); fileline = (char*)myalloc(sizeof(char)*(MAXFIRSTLINELEN+1)); if (fontfile.ReadString(fileline,MAXFIRSTLINELEN+1)==NULL) { fileline[0] = '\0'; } if (MYSTRLEN(fileline)>0 ? fileline[MYSTRLEN(fileline)-1]!='\n' : 0) { skiptoeol(fontfile); } numsread = sscanf(fileline,"%*c%c %d %*d %d %d %d %d %d", &hardblank,&charheight,&maxlen,&smush,&cmtlines, &ffright2left,&smush2); myfree(fileline); if (strcmp(magicnum,FONTFILEMAGICNUMBER) || numsread<5) ThrowErrorException ("Not a FIGlet 2 font file"); for (i=1;i<=cmtlines;i++) { skiptoeol(fontfile); } if (numsread<6) { ffright2left = 0; } if (numsread<7) { /* if no smush2, decode smush into smush2 */ if (smush == 0) smush2 = SM_KERN; else if (smush < 0) smush2 = 0; else smush2 = (smush & 31) | SM_SMUSH; } if (charheight<1) { charheight = 1; } if (maxlen<1) { maxlen = 1; } maxlen += 100; /* Give ourselves some extra room */ if (smushoverride == SMO_NO) smushmode = smush2; else if (smushoverride == SMO_FORCE) smushmode |= smush2; if (right2left<0) { right2left = ffright2left; } if (justification<0) { justification = 2*right2left; } fileline = (char*)myalloc(sizeof(char)*(maxlen+1)); /* Allocate "missing" character */ fcharlist = (fcharnode*)myalloc(sizeof(fcharnode)); fcharlist->ord = 0; fcharlist->thechar = (char**)myalloc(sizeof(char*)*charheight); fcharlist->next = NULL; for (row=0;row<charheight;row++) { fcharlist->thechar[row] = (char*)myalloc(sizeof(char)); fcharlist->thechar[row][0] = '\0'; } for (theord=' ';theord<='~';theord++) { readfontchar(fontfile,theord,fileline,maxlen); } for (theord=0;theord<=6;theord++) { readfontchar(fontfile,deutsch[theord],fileline,maxlen); } while (fontfile.ReadString(fileline,maxlen+1)==NULL?0: sscanf(fileline,"%li",&theord)==1) { readfontchar(fontfile,theord,fileline,maxlen); } myfree(fileline); }