Failure to create two sibling nodes in the root node using libxml2 writer handler - libxml2

I am new to libxml2 trying to generate XML files for the first time. But unable to create sibling node in the root node when try to create an XML file via testWriter.c link,The libxml2 will print an error message.
I want to create this example xml file. The point that there are sibling nodes in the root node:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!--child1 comment-->
<child1>
<element11>value11</element11>
<element11>12</element11>
</child1>
<!--child2 comment-->
<child2>
<element21>value21</element21>
<element22>22</element22>
</child2>
</root>
My writer handler code:
static void
gen_child1(xmlTextWriterPtr writer) {
char buf[64];
// comment
xmlTextWriterWriteComment(writer, BAD_CAST "child1 comment");
// start
if( xmlTextWriterStartElement(writer, BAD_CAST "child1") < 0 )
return;
// add a child element
xmlTextWriterWriteElement(writer, BAD_CAST "element11", BAD_CAST "value11");
// add a child element
(void) snprintf(buf, sizeof buf, "%d", 12);
xmlTextWriterWriteElement(writer, BAD_CAST "element12", BAD_CAST buf);
// start new node
if( xmlTextWriterStartElement(writer, BAD_CAST "element13") < 0 )
return;
xmlTextWriterWriteElement(writer, BAD_CAST "element131", BAD_CAST "value131");
// end new node
xmlTextWriterEndElement(writer);
// end
xmlTextWriterEndElement(writer);
}
static void
gen_child2(xmlTextWriterPtr writer) {
char buf[64];
// comment
xmlTextWriterWriteComment(writer, BAD_CAST "child2 comment");
// start
if( xmlTextWriterStartElement(writer, BAD_CAST "child2") < 0 )
return;
// add a child element
xmlTextWriterWriteElement(writer, BAD_CAST "element21", BAD_CAST "value21");
// add a child element
(void) snprintf(buf, sizeof buf, "%d", 22);
xmlTextWriterWriteElement(writer, BAD_CAST "element22", BAD_CAST buf);
// start new node
if( xmlTextWriterStartElement(writer, BAD_CAST "element23") < 0 )
return;
xmlTextWriterWriteElement(writer, BAD_CAST "element231", BAD_CAST "value231");
// end new node
xmlTextWriterEndElement(writer);
// end
xmlTextWriterEndElement(writer);
}
static void
gen_doc(void) {
xmlTextWriterPtr writer = NULL;
xmlDocPtr doc;
xmlNodePtr root;
if( !(doc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION)) )
puts("xmlNewDoc() failure");
if( !(root = xmlNewDocNode(doc, NULL, BAD_CAST "root", NULL)) )
puts("xmlNewDocNode() failure");
xmlDocSetRootElement(doc, root);
// create writer
if( !(writer = xmlNewTextWriterTree(doc, root, 0)) )
puts("xmlNewTextWriterTree() failure");
// start doc
if( xmlTextWriterStartDocument(writer, NULL, ENCODING, NULL) < 0 )
puts("xmlTextWriterStartDocument() failure");
gen_child1(writer);
gen_child2(writer);
// end doc
xmlTextWriterEndDocument(writer);
// free writer
xmlFreeTextWriter(writer);
print_doc(doc);
}
Libxml2 print this error message:
# This is Libxml2 output:
Entity: line 2: parser error : Extra content at the end of the document
nt13><element131>value131</element131></element13></child1><!--child2 comment-->
^
error : xmlTextWriterWriteDocCallback : XML error 5 !
I/O error : flush error
error : xmlTextWriterCloseDocCallback : XML error 5 !
# This is my print_doc(doc) output:
Length: 224
<?xml version="1.0" encoding="UTF-8"?>
<root><!--child1 comment--><child1><element11>value11</element11><element12>12</element12><element13><element131>value131</element131></element13></child1></root>
<!--child2 comment-->
I will succeed without using the writer handler, this the code:
static xmlNodePtr
gen_child1(xmlNsPtr _ns, const xmlChar *_name) {
xmlNodePtr retval = xmlNewNode(_ns, _name);
char buf[64];
if( retval ) {
xmlNewTextChild(retval, _ns, BAD_CAST "element11", BAD_CAST "value11");
(void) snprintf(buf, sizeof buf, "%d", 12);
xmlNewTextChild(retval, _ns, BAD_CAST "element11", BAD_CAST buf);
}
return retval;
}
static xmlNodePtr
gen_child2(xmlNsPtr _ns, const xmlChar *_name) {
xmlNodePtr retval = xmlNewNode(_ns, _name);
char buf[64];
if( retval ) {
xmlNewTextChild(retval, _ns, BAD_CAST "element21", BAD_CAST "value21");
(void) snprintf(buf, sizeof buf, "%d", 22);
xmlNewTextChild(retval, _ns, BAD_CAST "element22", BAD_CAST buf);
}
return retval;
}
static void
gen_doc(void) {
xmlTextWriterPtr writer = NULL;
xmlDocPtr doc;
xmlNodePtr root;
if( !(doc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION)) )
puts("xmlNewDoc() failure");
if( !(root = xmlNewDocNode(doc, NULL, BAD_CAST "root", NULL)) )
puts("xmlNewDocNode() failure");
xmlDocSetRootElement(doc, root);
xmlAddChild(root, xmlNewComment(BAD_CAST "child1 comment"));
xmlAddChild(root, gen_child1(NULL, BAD_CAST "child1"));
xmlAddChild(root, xmlNewComment(BAD_CAST "child2 comment"));
xmlAddChild(root, gen_child2(NULL, BAD_CAST "child2"));
print_doc(doc);
xmlFreeDoc(doc);
}
I want to know what i did wrong when using the writer handler?

xmlNewTextWriterTree has never been implemented correctly in libxml2.
The xmlTextWriter API should only be used to write documents in serialized form. Functions like xmlNewTextWriterTree or xmlNewTextWriterDoc serialize and reparse XML which is really inefficient. It's better to build documents using the "tree" API like in your working example.
You could open a bug report, but this badly designed part of the code base is unlikely to get fixed.

Related

C++ Hashtable issues within a nested switch case

So i am having an issue with a hashtable functions. In the main function the hashtables functions(removeitem, insertItem, and printTable) work with no issue but when i attempt to call them within another function AdminMenu they do not seem to work. For example when I run the program i can get the AdminMenu with no issues but once in the Admin menu a selection of an option produces the cout statement but does not complete the function. For example when you select 3 to print table nothing is output but the number 3. This function works when the function is called at the start of main but calling it inside the nested switch case adn it does not preform the function of printTable just outputs the selection 3.
#include<list>
#include<limits>
#include<string>
using namespace std;
// GLOBAL VARIABLES
bool empMatch= false; //set to false
bool keyExists = false;//set to false
//HASH TABLE CLASS STRUCT
class HashTable{
private:
static const int hashGroups = 10; //total size of 10 can be increased for larger groups
list<pair<int, string>> table[hashGroups];
public:
bool isEmpty();
int hashFunction(int key);
void insertItem(int key, string value);
void removeItem(int key);
bool searchTable(int key,string value);
void printTable();
};
//HASH FUNCTION TO CHECK IF TABLE EMPTY
bool HashTable::isEmpty()
{
int sum{};
for(int i{}; i< hashGroups; i++){
sum += table[i].size();
}
if(!sum){
return true;
}
return false;
}
//HASH FUNCTION
int HashTable::hashFunction(int key){
return key % hashGroups;
}
//HASH FUNCTION FOR INSERT VALUE
void HashTable::insertItem(int key, string value){
int hashValue = hashFunction(key);
auto& cell = table[hashValue];
auto tItr = begin(cell);
for(; tItr != end(cell); tItr++){
if(tItr->first==key){
keyExists = true; //if key exists replace value
tItr->second = value; //becomes value of input
cout<<"Warning key exists. value replaced\n";
break;
}
}
if (!keyExists){// If key does not exist then put back key and value
cell.emplace_back(key,value);
}
return ;
}
//HASH FUNCTION REMOVE
void HashTable::removeItem(int key){
int hashValue = hashFunction(key);
auto& cell = table[hashValue];
auto tItr = begin(cell);
for(; tItr != end(cell); tItr++){
if(tItr->first==key){
keyExists = true;
tItr = cell.erase(tItr);
cout<<"item removed\n";
break;
}
}
if(!keyExists){
cout<<"warning key not found";
}
return;
}
//HASH SEARCH TABLE FUNCTION FOR USER INPUT KEY AND USER INPUT VALUE
bool HashTable::searchTable(int key, string value){
int hashValue = hashFunction(key); //hash function to key input
auto& cell = table[hashValue];
auto tItr = begin(cell); //iterator
for(; tItr != end(cell); tItr++){
if(tItr->first==key){
keyExists = true;
if(keyExists){
if(tItr->second==value){//tests value of input is matching
empMatch=true;
}
else{
cout<<"access denied\n";
empMatch=false;
}
}
if(!keyExists){
cout<<"warning key not found\n";
empMatch= false;
}
}
}
return empMatch;
}
//HASH PRINT TABLE FUNCTION
void HashTable::printTable(){
for (int i{}; i< hashGroups ; i++){
if (table[i].size() == 0) continue;
auto tItr = table[i].begin();
for(;tItr !=table[i].end(); tItr++){
cout<<"info key : "<< tItr->first<<" value "<< tItr->second<<endl;
}
}
return;
}
//ADMIN MENU AND FUNCTIONS
void AdminMenu(){
int adminChoice=0;
int adminKey =0;
string adminValue;
HashTable HT;
cout<<"Please select from the following menu:\n";
cout<<"Option 1 insert user\n";
cout<<"Option 2 remove user\n";
cout<<"Option 3 Print user list\n";
cout<<"OPtion 4 Exit\n";
cin>>adminChoice;
switch(adminChoice){
case 1:
cout<<"Please enter employee id (whole number integer) to insert\n";
cin>>adminKey;
cout<<"Please enter password for employee id\n";
cin>>adminValue;
HT.insertItem(adminKey,adminValue);// DOESNT SEEM TO WORK
cout<<"insertion complete\n";
AdminMenu();
case 2:
cout<<"Please enter employee id (whole number integer) to remove\n";
cin>>adminKey;
HT.removeItem(adminKey); //DOESNT' SEEM TO WORK
cout<<"removal complete\n";
AdminMenu();
case 3:
HT.printTable(); //DOESN'T SEEM TO WORK.
AdminMenu();
case 4:
exit(0);
break;
}
}
//TODO implement a function that checks password against database or hashmap
void DisplayInfo(){
string clients[2][5] = {{"Bob Jones","Sarah Davis","Amy Friendly","Johnny Smith","Carol Spears"},{"2","2","1","1","2"}};
cout << "You chose 1\n" << "Client's Name Service Selected (1 = Brokerage, 2 = Retirement)\n";
for(int i=0;i<5;i++) {
cout << clients[0][i] << " selected option " << clients[1][i] << endl;
}
}
void changeCustomerChoice(){
string clients[2][5] = {{"Bob Jones","Sarah Davis","Amy Friendly","Johnny Smith","Carol Spears"},{"","2","1","1","2"}};
int temp= 0; //intialized at 0
cout << "You chose 2\n";
cout << "Enter the number of client you wish to change : \n";
cin >> temp; //this will check the type of input by the user.
while(1){ //this is an infinite check for the cin
if (cin.fail()){//this returns true when input failure occurs
cin.clear();// this clears the error state of the buffer
cin.ignore(numeric_limits<streamsize>::max(),'\n');//ignores the first instance of error
cout<<"You have entered the wrong input";
break;
}
if(temp>5||temp<1){
cin.clear();
cout<<"Selection out of range";
break;
}
if(!cin.fail()){// allow selection of services if input is correct
cout << "Please enter the client's new service choice (1 = Brokerage, 2 = Retirement)\n";
cin >> clients[1][temp-1]; //input needs to be adjusted to limit only 1 or 2 for change to new service
cout << "Changed option to : "<<clients[1][temp-1];
break;
}
}
}
int main()
{
HashTable HT;
int empNum= 0;
string empPass;
int userChoice;
int adminPass;
//insert values to i dont have a empty table
HT.insertItem(905,"Jim");
HT.insertItem(9415,"bob");
HT.insertItem(5105,"sany");
HT.insertItem(685,"Jasdfm");
HT.insertItem(9565,"amrk");
HT.insertItem(905,"trick");
HT.printTable();
cout<<"please enter employee number\n";
cout<<"please enter employee password\n";
cin>>empNum;
cin>>empPass;
HT.searchTable(empNum,empPass);
if(empMatch){
cout<<"access granted";
cout<<"What would you like to do?\n";
cout<<"DISPLAY the client list (enter1)\n";
cout<<"CHANGE a clients choice (enter2)\n";
cout<<"Admin functions (enter3)\n";
cout<<"Exit the program(enter4)\n";
cin>> userChoice;
switch(userChoice){
case 1:
DisplayInfo();
main();
break;
case 2:
changeCustomerChoice();
main();
break;
case 3:
cout<<"Please enter admin password\n";
cin>> adminPass;
if(adminPass == 5691){
AdminMenu();
break;
}
else{
break;
}
case 4:
exit(0); //exit program
default: //secures input from usering being malicious in nature
cout << "Invalid Selection" << endl;
cin.clear(); //clears the error state of the buffer
main(); // got back to main function
}
}
if(!empMatch){
cout<<"The creditionals you have entered do not match\n";
exit(0);
}
return 0;
`

How does QT get the ico of a process

I want to make a process list window, so I traverse the process list, but I don’t know how to get the icon and display it in the listWidget
This is my code:
#include <windows.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <iostream>
HANDLE hSnap = CreateToolhelp32Snapshot(PROCESS_ALL_ACCESS, 0);
if( hSnap != INVALID_HANDLE_VALUE )
{
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
if( Process32First(hSnap, &pe) )
{
DWORD curID = GetCurrentThreadId();
do{
if(pe.th32ProcessID && pe.th32ProcessID != curID)
{
QListWidgetItem *it = new QListWidgetItem(
/* icon */
PaddingZero(QString::number(pe.th32ProcessID, 16)).toUpper() +"-"+ QString::fromWCharArray(pe.szExeFile),
ui->listWidget
);
ui->listWidget->addItem(it);
//printf("name: %ls, id: %d\n",pe.szExeFile,pe.th32ProcessID);
}
}while( Process32Next(hSnap, &pe) );
}
}
CloseHandle(hSnap);
How can I get the ico of each process.
After a few days, I finally found the answer
HANDLE hSnap = CreateToolhelp32Snapshot(PROCESS_ALL_ACCESS, 0);
if( hSnap != INVALID_HANDLE_VALUE )
{
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
if( Process32First(hSnap, &pe) )
{
do{
if(pe.th32ProcessID != GetCurrentProcessId())
{
// https://forum.qt.io/topic/62866/getting-icon-from-external-applications/5
// https://stackoverflow.com/questions/63653786/error-using-getmodulefilenameexa-function-in-qt?noredirect=1#comment112561229_63653786
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe.th32ProcessID);
wchar_t lpFilename[1024];
GetModuleFileNameExW(hProcess, NULL, lpFilename, sizeof(lpFilename));
CloseHandle(hProcess);
QFileInfo fin( QString::fromWCharArray(lpFilename) );
QFileSystemModel *model = new QFileSystemModel;
model->setRootPath(fin.path());
QIcon ic = model->fileIcon(model->index(fin.filePath()));
QListWidgetItem *it = new QListWidgetItem(
ic,
PaddingZero(QString::number(pe.th32ProcessID, 16)).toUpper() +
"-" +
QString::fromWCharArray(pe.szExeFile),
ui->list
);
ui->list->addItem(it);
//printf("name: %ls, id: %d\n",pe.szExeFile,pe.th32ProcessID);
}
}while( Process32Next(hSnap, &pe) );
}
}
CloseHandle(hSnap);

Add additional xsd schemas with libXml2

I have a xml and schema which I want to validate. I don't want schema to be stored in file, but in database location. I use xmlSchemaNewMemParserCtxt to parse the schema. The problem is that this schema references another schema for basic types: <xs:include schemaLocation="CommonTypes.xsd"/>, which libXml2 searches in the current working directory. Is there any way to supply these additional schemas in memory buffer?
xmlRegisterInputCallbacks is what you're probably looking for.
The advantage, they let you construct some kind of a virtual I/O layer. The disadvantage, inputcallbacks are set globally (there is however xmlPopInputCallbacks and xmlCleanupInputCallbacks).
The code below (built upon code from http://knol2share.blogspot.be) demonstrates the use of xmlRegisterInputCallbacks.
All xml and xsd files are loaded from the file system, except when the URI contains "DataTypes.xsd" the schema is fetched from a string. (since schemaLocation is only a hint one could for example prefix schema's
"test.xsd": the main xml schema (please ignore the reference to peacelane.org, namespaces are from a hobby project, just occurred to me now www.peacelane.org might exist, apparently it does...)
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://peacelane.org/ApplianceType/config/45/LIGHTING1/ARC"
xmlns:dt="http://peacelane.org/ApplianceType/config/45/DataTypes"
targetNamespace="http://peacelane.org/ApplianceType/config/45/LIGHTING1/ARC"
elementFormDefault="qualified">
<import namespace="http://peacelane.org/ApplianceType/config/45/DataTypes" schemaLocation="DataTypes.xsd" />
<complexType name="ConfigType">
<sequence>
<element name="housecode" type="dt:char" />
</sequence>
</complexType>
<element name="Config" type="tns:ConfigType"/>
</schema>
"test.xml": a test xml to validate
<?xml version="1.0"?>
<Config xmlns="http://peacelane.org/ApplianceType/config/45/LIGHTING1/ARC">
<housecode>A</housecode>
</Config>
"main.c": the actual code (update the paths for "XMLFileName" and "XSDFileName")
#define LIBXML_SCHEMAS_ENABLED
#include <libxml/xmlschemastypes.h>
#include <stdio.h>
static const char *databaseSchema =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
" <schema elementFormDefault=\"qualified\" xmlns:tns=\"http://peacelane.org/ApplianceType/config/45/DataTypes\" targetNamespace=\"http://peacelane.org/ApplianceType/config/45/DataTypes\" xmlns=\"http://www.w3.org/2001/XMLSchema\">"
" <simpleType name=\"char\">"
" <restriction base=\"string\">"
" <length value=\"1\" />"
" </restriction>"
" </simpleType>"
" </schema>";
//-----------------------------------------------------------------------------
//-- SQL Callbacks (~ simulated db actions)
//-----------------------------------------------------------------------------
static void* sqlOpen(const char * URI) {
return ((void *) databaseSchema );
}
static int sqlClose(void * context) {
return (0);
}
static int sqlRead(void * context, char * buffer, int len) {
const char* result= (const char *) context;
int rlen = strlen(result);
memcpy(buffer, result, rlen);
return rlen +1;
}
static int sqlMatch(const char * URI) {
if ((URI != NULL )&& (strstr(URI, "DataTypes.xsd") != NULL) )return 1;
return 0;
}
//-----------------------------------------------------------------------------
//-- File callbacks
//-----------------------------------------------------------------------------
static void* fileOpen(const char * URI) {
if (URI == NULL )
return (NULL );
FILE* fh = fopen(URI, "rt");
return ((void *) fh);
}
static int fileClose(void * context) {
FILE* fh = (FILE*) context;
if (fh != NULL )
fclose(fh);
return (0);
}
static int fileRead(void * context, char * buffer, int len) {
FILE* fh = (FILE*) context;
fseek(fh, 0L, SEEK_END);
long flen = ftell(fh);
rewind(fh);
if (buffer != NULL )
fread(buffer, flen, 1, fh);
return flen + 1;
}
static int fileMatch(const char * URI) {
if ((URI != NULL ))
if (strstr(URI, "DataTypes.xsd") == NULL ) {
return (1);
}
return (0);
}
//-----------------------------------------------------------------------------
//-- Main
//-----------------------------------------------------------------------------
int main(int argc, char *argv[]) {
xmlDocPtr doc;
xmlSchemaPtr schema = NULL;
xmlSchemaParserCtxtPtr ctxt;
char *XMLFileName =
"/home/dogguts/Projects/libxml2tests/xsdparse/Debug/test.xml";
char *XSDFileName =
"/home/dogguts/Projects/libxml2tests/xsdparse/Debug/test.xsd";
xmlLineNumbersDefault(1);
if (xmlRegisterInputCallbacks(fileMatch, fileOpen, fileRead, fileClose)
< 0) {
fprintf(stderr, "failed to register File handler\n");
exit(1);
}
if (xmlRegisterInputCallbacks(sqlMatch, sqlOpen, sqlRead, sqlClose) < 0) {
fprintf(stderr, "failed to register SQL handler\n");
exit(1);
}
ctxt = xmlSchemaNewParserCtxt(XSDFileName);
xmlSchemaSetParserErrors(ctxt, (xmlSchemaValidityErrorFunc) fprintf,
(xmlSchemaValidityWarningFunc) fprintf, stderr);
schema = xmlSchemaParse(ctxt);
xmlSchemaFreeParserCtxt(ctxt);
xmlSchemaDump(stdout, schema);
doc = xmlReadFile(XMLFileName, NULL, 0);
if (doc == NULL ) {
fprintf(stderr, "Could not parse %s\n", XMLFileName);
} else {
xmlSchemaValidCtxtPtr ctxt;
int ret;
ctxt = xmlSchemaNewValidCtxt(schema);
xmlSchemaSetValidErrors(ctxt, (xmlSchemaValidityErrorFunc) fprintf,
(xmlSchemaValidityWarningFunc) fprintf, stderr);
ret = xmlSchemaValidateDoc(ctxt, doc);
if (ret == 0) {
printf("%s validates\n", XMLFileName);
} else if (ret > 0) {
printf("%s fails to validate\n", XMLFileName);
} else {
printf("%s validation generated an internal error\n", XMLFileName);
}
xmlSchemaFreeValidCtxt(ctxt);
xmlFreeDoc(doc);
}
if (schema != NULL )
xmlSchemaFree(schema);
xmlSchemaCleanupTypes();
xmlCleanupParser();
xmlMemoryDump();
return (0);
}
Notice that, for brevity, the above code doesnt' perform any checks wether (file, memory,...) operations succeeded.
This is a better example how to do it: io1.c
http://www.xmlsoft.org/examples/
It saves a lot of time when you can find what is good way to return value from Read function.

find_if in MFC container with iterator derived from std::iterator

I have a working iterator for MFC CObList - BaseMFCIter. It works for iterating in loop but i still didn't managed to make ListIter to work properly with STL algorithm find_if.
Code
#include < iterator >
#include "afxwin.h"
#include "afxtempl.h"
#include <iostream>
#include <algorithm>
#include <cstdlib>
class myCObject : public CObject
{
public:
myCObject( std::string val )
{
x = val;
}
std::string x;
};
template < typename Item, class Cont, class Key = POSITION >
class BaseMFCIter : public std::iterator < std::input_iterator_tag, Item >
{
public:
// Define types for the 2 member functions to be used:
typedef Key (Cont::*GetFirstFunctionPtr) () const;
typedef Item (Cont::*GetNextFunctionPtr) (Key&) const;
// Default constructor, makes a null iterator, equal to BaseMFCIter::end()
BaseMFCIter() : m_pCont(0), m_Pos(0), m_GetFirstFunc(0), m_GetNextFunc(0), m_End(true) {}
// Constructor taking pointer to container and the iteration functions
BaseMFCIter(Cont* pCont, GetFirstFunctionPtr pFF, GetNextFunctionPtr pNF)
: m_pCont(pCont), m_Pos(0), m_GetFirstFunc(pFF), m_GetNextFunc(pNF)
{ init(); }
// Copy constructor, initialises iterator to first element
BaseMFCIter(const BaseMFCIter& vi) : m_pCont(vi.m_pCont), m_Pos(0),
m_GetFirstFunc(vi.m_GetFirstFunc), m_GetNextFunc(vi.m_GetNextFunc)
{ init(); }
// Assignment operator, initialises iterator to first element
BaseMFCIter& operator=(const BaseMFCIter& vi)
{
m_pCont = vi.m_pCont;
m_GetFirstFunc = vi.m_GetFirstFunc;
m_GetNextFunc = vi.m_GetNextFunc;
init();
return *this;
}
bool operator == (const BaseMFCIter& rhs) const
{ return (m_Pos == rhs.m_Pos && m_End == rhs.m_End); }
bool operator != (const BaseMFCIter& rhs) const
{ return !operator==(rhs); }
BaseMFCIter& operator ++ () { advance(); return *this; }
BaseMFCIter& operator ++ (int) { BaseMFCIter ret(*this); advance(); return ret; }
Item operator * () { return m_Item; }
Item operator -> () { return m_Item; }
static BaseMFCIter end () { return BaseMFCIter(); } // end() returns default null iterator
private:
Item m_Item; // Current item from container
Cont* m_pCont; // Pointer to container
Key m_Pos; // Key to item in container
bool m_End; // Flag to indicate end of container reached
// Pointers to container iteration functions
GetFirstFunctionPtr m_GetFirstFunc;
GetNextFunctionPtr m_GetNextFunc;
// Use container GetFirst & GetNext functions to set to first element, or end() if not found
void init()
{
m_Pos = 0;
m_End = true;
if (m_pCont && m_GetFirstFunc != 0)
{
m_Pos = (m_pCont->*m_GetFirstFunc)();
advance();
}
}
// Use container GetNext function to find next element in container
void advance()
{
m_End = m_Pos ? false : true;
m_Item = (m_Pos && m_pCont && m_GetNextFunc != 0) ?
(m_pCont->*m_GetNextFunc)(m_Pos) : Item();
}
};
struct Container : public CObList
{
myCObject* GetNext(POSITION& rPosition)
{
return dynamic_cast<myCObject*>(CObList::GetNext(rPosition));
}
myCObject const* GetNext(POSITION& rPosition) const
{
return dynamic_cast<const myCObject*>(CObList::GetNext(rPosition));
}
};
class ListIter : public BaseMFCIter < const myCObject*, Container, POSITION >
{
public:
ListIter( Container* pObj = 0)
: BaseMFCIter< const myCObject*, Container, POSITION >
(pObj, &CObList::GetHeadPosition, &Container::GetNext)
{
}
};
struct Comparator
{
std::string stringToCompare;
bool operator() ( const myCObject* lhs )
{
return (bool) lhs->x.compare( stringToCompare );
}
};
void main( )
{
myCObject* m = new myCObject( "one" );
myCObject* n = new myCObject( "two" );
myCObject* p = new myCObject( "three" );
myCObject* q = new myCObject( "four" );
Container cont;
cont.AddHead( m );
cont.AddHead( n );
cont.AddHead( p );
cont.AddHead( q );
Comparator pred;
pred.stringToCompare = "1";
ListIter iter = ListIter( &cont );
ListIter endIter = ListIter( );
ListIter foundIter = std::find_if( iter, endIter, pred );
std::cout << "foundIter x is: " << foundIter->x.c_str() << std::endl;
}
gives me foundIter x is: four. This propably happens because of the way the end position is defined so
_InIt _Find_if(_InIt _First, _InIt _Last, _Pr _Pred)
{ // find first satisfying _Pred
_DEBUG_RANGE(_First, _Last);
_DEBUG_POINTER(_Pred);
for (; _First != _Last; ++_First)
if (_Pred(*_First))
break;
return (_First);
}
doesn't iterate properly but i can't figure out how to fix it.
A number of issues fixed:
(bool) lhs->x.compare( stringToCompare ) returns true _whenever the string don't match** (see string::compare)
you were searching for "1", which doesn't exist
since the predicate was wrong, you received the first match, which was the first element, also inserted the last, and the name was "four" :)
you didn't check whether a valid match was found (dereferencing the end-iterator is illegal and may crash your program or do worse things: undefined behaviour)
you had a superflous x.c_str() in the output statement
I changed the Compare predicate around to be more idiomatic:
initialize stringToCompare from the constructor
make the field const
make the operator() a const method
This should do the trick (untested code, I'm not near a compiler the coming hours)
Update
After arriving home, I finally broke out the debugger to track that strange behaviour (see comments).
To my dismay, I found out that the BaseMFCIter was designed by someone with very limited understanding of what an iterator is: the copy constructor and assignment operator were completely wrong: they had the effect of creating a new begin iterator - for the same collection. This however, means that an iterator could never be returned from a function.
Therefore, I fixed it (first by implementing it right, later by removing the now-redundant constructor and operator= in favour of the compiler-generated default implementations).
See the full history of my and your edits:
git clone git://gist.github.com/1353471.git
sehe 11 minutes ago rely on default generated copy constructor and assignment instead
sehe 12 minutes ago fixed broken copy constructor and assignment
sehe 65 minutes ago tentative
Dmitry 73 minutes ago Attempt at find_if with predicate
sehe Heeren 25 hours ago Fixed and Tested (VS2010)
sehe 25 hours ago ( STL iterator for MFC container CObList )
#include "afxwin.h"
#include "afxtempl.h"
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <iterator>
class myCObject : public CObject
{
public:
myCObject( const std::string& val ) { x = val; }
std::string x;
};
template < typename Item, class Cont, class Key = POSITION >
class BaseMFCIter : public std::iterator < std::input_iterator_tag, Item >
{
public:
// Define types for the 2 member functions to be used:
typedef Key (Cont::*GetFirstFunctionPtr) () const;
typedef Item (Cont::*GetNextFunctionPtr) (Key&) const;
// Default constructor, makes a null iterator, equal to BaseMFCIter::end()
BaseMFCIter() : m_pCont(0), m_Pos(0), m_GetFirstFunc(0), m_GetNextFunc(0), m_End(true) {}
// Constructor taking pointer to container and the iteration functions
BaseMFCIter(Cont* pCont, GetFirstFunctionPtr pFF, GetNextFunctionPtr pNF)
: m_pCont(pCont), m_Pos(0), m_GetFirstFunc(pFF), m_GetNextFunc(pNF)
{ init(); }
bool operator == (const BaseMFCIter& rhs) const
{ return (m_Pos == rhs.m_Pos && m_End == rhs.m_End); }
bool operator != (const BaseMFCIter& rhs) const
{ return !operator==(rhs); }
BaseMFCIter& operator ++ () { advance(); return *this; }
BaseMFCIter& operator ++ (int) { BaseMFCIter ret(*this); advance(); return ret; }
Item operator * () { return m_Item; }
Item operator -> () { return m_Item; }
static BaseMFCIter end () { return BaseMFCIter(); } // end() returns default null iterator
private:
Item m_Item; // Current item from container
Cont* m_pCont; // Pointer to container
Key m_Pos; // Key to item in container
bool m_End; // Flag to indicate end of container reached
// Pointers to container iteration functions
GetFirstFunctionPtr m_GetFirstFunc;
GetNextFunctionPtr m_GetNextFunc;
// Use container GetFirst & GetNext functions to set to first element, or end() if not found
void init()
{
m_Pos = 0;
m_End = true;
if (m_pCont && m_GetFirstFunc != 0)
{
m_Pos = (m_pCont->*m_GetFirstFunc)();
advance();
}
}
// Use container GetNext function to find next element in container
void advance()
{
m_End = m_Pos ? false : true;
m_Item = (m_Pos && m_pCont && m_GetNextFunc != 0) ?
(m_pCont->*m_GetNextFunc)(m_Pos) : Item();
}
};
struct Container : public CObList
{
myCObject* GetNext(POSITION& rPosition)
{
return dynamic_cast<myCObject*>(CObList::GetNext(rPosition));
}
myCObject const* GetNext(POSITION& rPosition) const
{
return dynamic_cast<const myCObject*>(CObList::GetNext(rPosition));
}
};
class ListIter : public BaseMFCIter < const myCObject*, Container, POSITION >
{
public:
ListIter( Container* pObj = 0)
: BaseMFCIter< const myCObject*, Container, POSITION >
(pObj, &CObList::GetHeadPosition, &Container::GetNext)
{
}
};
struct Comparator
{
Comparator(const std::string& compareTo) : stringToCompare(compareTo) {}
bool operator() ( const myCObject* lhs ) const
{
return 0 == lhs->x.compare( stringToCompare );
}
private:
const std::string stringToCompare;
};
void main( )
{
myCObject* m = new myCObject( "one" );
myCObject* n = new myCObject( "two" );
myCObject* p = new myCObject( "three" );
myCObject* q = new myCObject( "four" );
Container cont;
cont.AddHead( m );
cont.AddHead( n );
cont.AddHead( p );
cont.AddHead( q );
Comparator pred("three");
ListIter iter = ListIter(&cont),
endIter = ListIter( );
ListIter foundIter = std::find_if( iter, endIter, pred );
if (endIter != foundIter)
{
std::cout << "foundIter x is: " << foundIter->x << std::endl;
}
else
{
std::cout << "not found" << std::endl;
}
}

SQLite and UTF8

I have a strange problem. Cant add function to sqlite/ Write on c++/Qt.
Function should do upper to Utf-8 simbols;
this->db = QSqlDatabase::addDatabase("QSQLITE");
this->db.setDatabaseName(db);
this->db.open();
QVariant v = this->db.driver()->handle();
sqlite3 *handler = *static_cast<sqlite3 **>(v.data());
sqlite3_create_function( handler, "myUpper", 1, SQLITE_ANY, NULL, myFunc, NULL, NULL )
and the function is:
void myFunc( sqlite3_context * ctx, int argc, sqlite3_value ** argv )
{
if( argc != 1 ) return;
QString str;
switch(sqlite3_value_type(argv[0]))
{
case SQLITE_NULL:
{
sqlite3_result_text( ctx, "NULL", 4, SQLITE_STATIC );
break;
}
case SQLITE_TEXT:
{
QString wstr((char*)sqlite3_value_text16(argv[0]));
wstr = wstr.toUpper();
sqlite3_result_text16( ctx, wstr.toStdString().c_str(), wstr.size() , SQLITE_TRANSIENT );
break;
}
default:
sqlite3_result_text( ctx, "NULL", 4, SQLITE_STATIC );
break;
}
}
You didn't specify the problem, but I suppose you should pass a pointer to the function:
sqlite3_create_function(handler, "myUpper", 1, SQLITE_ANY, NULL, &myFunc, NULL, NULL)
EDIT:
I you're passing to the function wstr.toStdString().c_str(). This is not allowed because the pointer returned is only temporary and will go out of scope. What I would do is:
...
case SQLITE_TEXT: {
QString wstr((char*)sqlite3_value_text(argv[0]));
wstr = wstr.toUpper();
QByteArray array = wstr.toLocal8Bit();
const char* cstr = array.data();
sqlite3_result_text(ctx, cstr, wstr.size() , SQLITE_TRANSIENT);
break;
}
...
I didn't try it so check this.

Resources