XML reader compile and link – cpp

From the post of the full code of the xml reader project, full code here.

Here is how to compile it up and also link to a basic main run method.

Compile up

g++ cppxmlreader.cpp -c

will create the cppxmlreader.o (which is the object file) if you do file on the object the outout would be

file cppxmlreader.o
cppxmlreader.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

and then using this code xmlreadmain.cpp

#include "cppxmlreader.h"
 
int main(int argv, char** argc)
{
    xmlReader xmlRead;
    xmlRead.loadFile("words.xml");
    xmlRead.printOuterXML();
    return 0;
}

This will include the header file of the cppxmlreader.h and then create a xmlReader object and load a basic file of words.xml and then print out the xml read in.

Here is the words.xml

<?xml version="1.0" encoding="UTF-8"?>
<words>
  <word attname="hi">merry</word>
  <word>old</word>
  <word>sole</word>
  <word>was</word>
  <word>he</word>
</words>

and to compile up the main run the cppxmlreader.o is the object file from the above compiling and the xmlreadmain.cpp is the main runner with -o being the output name of the executable.

g++ xmlreadmain.cpp cppxmlreader.o -o xmlreader

and if you run the xmlreader, the output should be

XML Reader Main Object (Xml main details)
XML Object
Tagname  :
Tagvalue :
Attribute 0 : Name : version Value : 1.0
Attribute 1 : Name : encoding Value : UTF-8
XML Reader xml details
XML Object
Tagname  :words
Tagvalue :
XML Object
Tagname  :word
Tagvalue :merry
Attribute 0 : Name : attname Value : hi
XML Object
Tagname  :word
Tagvalue :old
XML Object
Tagname  :word
Tagvalue :sole
XML Object
Tagname  :word
Tagvalue :was
XML Object
Tagname  :word
Tagvalue :he
XML Object
Tagname  :/words
Tagvalue :

XML reader full – cpp

Here is the full code for the header and class file from the xml reader project

Here is the cppxmlreader.h file.

#ifndef CPPXMLREADER_H
#define CPPXMLREADER_H
 
#include <string>
#include <vector>
 
// using the namespace std for the string type, vector
using namespace std;
 
const int CHARACTERLENGHT = 80;
const string BADXMLVERSION = "Xml version - first line ? - problem";
const string BADTAGNAME = "Tag name was not present";
const string BADXMLTAGEND = "End tag is not the same as tag name";
const string BADATTRIBUTE = "Attribute in wrong format attributeName=\"attributeValue\"";
 
struct xmlAttribute {
    string _attributeName, _attributeValue;
};
 
class xmlObject {
  private :
    string _tagName, _tagValue;
    vector<xmlAttribute> _attributes;
    bool _xmlMainDetails;
 
  public:
      xmlObject() { _xmlMainDetails = false;} ;
      xmlObject(string tag, string tValue, xmlAttribute attribute);
 
      void setTagName(string tagName);
      void setTagValue(string tagValue);
      void addAttributes(xmlAttribute attribute);
      void setAttributeVector(vector<xmlAttribute> setAtt);
      void setXmlMainDetails(bool value);
      bool getXmlMainDetails();
      void printOutXmlObject();
};
 
class xmlReader {
  protected:
    vector<xmlObject> _xmlMainDetails;
    vector<xmlObject> _xmlDetails;
 
  public: 
    xmlReader();
 
    // open file and read in the xml file and place into the _xmlDetails
    bool loadFile(string filename);
    void printOuterXML();
 
  private :
    xmlObject readLine(string xmlToSplitUp, string* tagName);
    string readUntilCharacter(string line, char characterStart, char characterEnd, string *returnLine);
    xmlAttribute getAttribute(string attributeString);
    vector<xmlAttribute> getAttributesFromString(string str);
};
 
 
#endif // CPPXMLREADER_H

Here is the cppxmlreader.cpp file

#include "cppxmlreader.h"
#include <iostream>
#include <string.h>
#include <fstream>
 
using namespace std;
 
/* xmlObject */
// constructor for xmlObject, if any details are passed whilst constructing 
xmlObject::xmlObject(string tag, string tValue, xmlAttribute attribute)
{
  _tagName = tag;
  _tagValue = tValue;
  _attributes.push_back(attribute);
}
 
// xml <tagname attributes="attributesvalue">VALUE</tagname>
// set the tag name
void xmlObject::setTagName(string tagName)
{
  _tagName = tagName;
}
 
// set tag value
void xmlObject::setTagValue(string tagValue)
{
  _tagValue = tagValue;
}
 
// add attributes to the vector attributes variable
void xmlObject::addAttributes(xmlAttribute attribute)
{
  _attributes.push_back(attribute);
}
 
// fill in the vector attributes variable.
void xmlObject::setAttributeVector(vector<xmlAttribute> setAtt)
{
  _attributes = setAtt;
}
 
// print out the xml object detais, with the attributes values.
void xmlObject::printOutXmlObject()
{
  cout << "XML Object" << endl;
  cout << "Tagname  :" << _tagName << endl;
  cout << "Tagvalue :" << _tagValue << endl;
  for (int i= 0; i < (int)_attributes.size(); i++)
  {
      cout << "Attribute " << i << " : Name : "<< _attributes.at(i)._attributeName << " Value : " << _attributes.at(i)._attributeValue << endl;
  }
}
 
// set the main set details value
void xmlObject::setXmlMainDetails(bool value)
{	
    _xmlMainDetails = value;
}
 
// get a boolean value to see if the xmlObject is the main <?xml .. ?> value
bool xmlObject::getXmlMainDetails()
{
  return _xmlMainDetails;
}
 
 
/*xmlReader*/
xmlReader::xmlReader()
{
}
 
// attribute is normally in the format of attributeName="attributeValue"
xmlAttribute xmlReader::getAttribute(string attributeString)
{
  xmlAttribute returnAttribute;
 
  // make sure that there is a = in the attribute string
  int findEqual = attributeString.find('=');
  if (findEqual > 0)
  {
    // set the attribute name to the substring till the equal
    returnAttribute._attributeName = attributeString.substr(0,findEqual);
    // make sure that there is some characters after the '=' sign.
    if (attributeString.length() > (findEqual+3))
    {
      returnAttribute._attributeValue = attributeString.substr(findEqual+2,(attributeString.length() - (findEqual +3)));
    }
    else
      throw BADATTRIBUTE;
  }else
    // if there does not appear to be ="" at the end of the string then throw a error.
    throw BADATTRIBUTE;
 
  return returnAttribute;
}
 
vector<xmlAttribute> xmlReader::getAttributesFromString(string str)
{
    vector<xmlAttribute> returnAtt;
    xmlAttribute attribute;
    int args;
    char st1[CHARACTERLENGHT];
 
    // args normally equals 1 because there is a attribute present
    // else there was no attribute there, just do one at a time
    args = sscanf(str.c_str(), "%s", st1);
    while (args  == 1 && (str.length() > 1)) {
      // see if there is a real attribute attributeName="attributeValue"
      try {
	attribute = getAttribute(st1);
	// push back in the vector array the attribute
	returnAtt.push_back(attribute);
      } catch (string errorStr)		// any errors
      {
	cout << "ERROR : " << errorStr << endl;
      }
      // re-do the string to pull out any more attributes.
      str = str.substr(strlen(st1));
      // see if there is any more attributes present.
      args = sscanf(str.c_str(), "%s", st1);
    }
    return returnAtt;
}
 
// scan through the xml string and pull out the tags and the attributes and value.
xmlObject xmlReader::readLine(string xmlToSplitUp, string* tagName)
{
  xmlObject returnObj;
  string returnLine, value, endTagName;
  int findXml;
 
  // pick out the tag name, if none then return and throw a bad tag name error.
  *tagName = readUntilCharacter(xmlToSplitUp, '<','>', &returnLine);
  if (tagName->length() ==0)
  {
     throw BADTAGNAME;
     return returnObj;
  }
 
  // if there is a xml version etc in the tagname then process the xml version encoding values.
  findXml=tagName->find("xml");
  if ((findXml > 0 && findXml < tagName->length()) && tagName->length() > 1 )
  {
    // this is the xml version etc.
    // there should be ? at each end of the xml version statement
    string xmlStr = readUntilCharacter(*tagName, '?','?', &returnLine);
    if (returnLine != "?") 
    {
      throw BADXMLVERSION;
      return returnObj;
    }
    // go passed the xml characters.
    returnLine = xmlStr.substr(findXml+3);
    // read any of the attributes from the string
    returnObj.setAttributeVector(getAttributesFromString(returnLine));
    // I am storing the version and any other xml details, so set the return value to store in the correct place.
    returnObj.setXmlMainDetails(true);
  }else if (tagName->length() > 1) 
  {
    // need to see if there is any attributes
    int findTagAtts = tagName->find(' ');
    if (findTagAtts < tagName->length())
    {
      // the attributes are passed the space character in the tagName variable
      string attributes = tagName->substr(findTagAtts);
      // store only the tagName in the tagName variable since pulled out the attributes
      *tagName = tagName->substr(0,findTagAtts);
      // get the attributes into a vector and store in the return object
      returnObj.setAttributeVector(getAttributesFromString(attributes));
    }
 
    if (returnLine.length() > 1)
    {
      // pull out the value in the xml line <tagname>VALUE</tagname>
      value = readUntilCharacter(returnLine,'>','<',&returnLine);
      returnObj.setTagValue(value);
    }
    if (returnLine.length() > 1)
    {
      // pick out the end tag name and make sure it is the same as the first one.
      endTagName = readUntilCharacter(returnLine,'<','>',&returnLine);
      string compareEndTag = "/"+*tagName;
      //if the end tag is not the same as the tag name then throw a error.
      if (endTagName != compareEndTag) 
      {
	throw BADXMLTAGEND;
      } 
    }
    returnObj.setTagName(*tagName);
 
   }
  return returnObj;
}
 
// pick out the characters between two character points, and also return the rest of the line.
string xmlReader::readUntilCharacter(string line, char characterStart, char characterEnd, string *returnLine)
{
  string returnString;
  // find the first occurrence of the character integer placement
  int firstChar = line.find(characterStart);
  // if there is one.
  if (firstChar >= 0)
  {
    // setup the return string, even if a second part cannot be found.
    returnString = line.substr(firstChar+1, (line.length()- firstChar)-1);
    int secChar = returnString.find(characterEnd);
    //if the secound part can be found
    if (secChar > 0)
    {
      *returnLine = returnString.substr(secChar, (returnString.length() - secChar));
      returnString = returnString.substr(0,secChar);
    }
  }
  return returnString;
}
 
// read in the XML file and place each line into the vector xmlObject 
bool xmlReader::loadFile(string filename)
{
  xmlObject xmlObj;
  string line, tagName;
 
  ifstream xmlfile(filename.c_str());
  if (xmlfile.is_open())
  {
      // if the xml version and also the encodingvalues are present.
      //getline(xmlfile,line);
 
      while (!xmlfile.eof())
      {
	  // pull out the start tag and compare against the endtag
	  getline(xmlfile,line);
	  try 
	  {
	    // pick out the xml details from line and return a xmlObject 
	    // to add to the vector array of xml objects
	    // also return the tagName if any futher processing is required.
	    xmlObj = readLine(line, &tagName);
	    // if there is ?xml version etc details present store, else store into the main xml details
	    if (xmlObj.getXmlMainDetails())
	    {
	      _xmlMainDetails.push_back(xmlObj);
	    }
	    else
	    {  
	      _xmlDetails.push_back(xmlObj);
	    }
	  }
	  // if any error occur during the reading of the xml line.
	  catch (string errorStr)
	  {
	    cout << "ERROR : " << errorStr << endl;
	  }
      }
 
      xmlfile.close();
  }
  else
  {
      cout << "Unable to open the file" << endl;
  }
}
 
/* print Out the outer XML values */
void xmlReader::printOuterXML()
{
    cout << "XML Reader Main Object (Xml main details) " << endl;
    for (int i =0; i < _xmlMainDetails.size(); i++)
      _xmlMainDetails.at(i).printOutXmlObject();
 
    cout << "XML Reader xml details" << endl;
    for (int i =0; i < _xmlDetails.size(); i++)
      _xmlDetails.at(i).printOutXmlObject();
}

Xml reader – cpp

The xml reader from the xmlreader in cpp joins together the xmlattribute and xmlobject and this last class, this one is the biggest because it does most of the work. So shall try and explain each part.

As before a xml is

<tagname attributesname="attributesvalue">value</tagname>

The main structure includes the xml definition ( ) in the _xmlMainDetails and the rest of the xml file is in _xmlDetails vectors of xmlObject.

The main file is loaded with the loadLoad ( filename ) and then printout the xml that has been loaded, shall have to do some more public functions to view etc the loaded xml file, but this is just the basics of a xml reader. The rest are private functions because they will load the xml file in the _xmlDetails variable.

class xmlReader {
  protected:
    vector<xmlObject> _xmlMainDetails;
    vector<xmlObject> _xmlDetails;
 
  public: 
    xmlReader();
 
    // open file and read in the xml file and place into the _xmlDetails
    bool loadFile(string filename);
    void printOuterXML();
 
  private :
    xmlObject readLine(string xmlToSplitUp, string* tagName);
    string readUntilCharacter(string line, char characterStart, char characterEnd, string *returnLine);
    xmlAttribute getAttribute(string attributeString);
    vector<xmlAttribute> getAttributesFromString(string str);
};

The BADATTRIBUTE are const string values that I have included at the bottom, but they are within a try {} catch {} code, so that it will throw a error to be catch.

The getAttribute, will try and obtain the attribute from a string parameter, e.g. if the string parameter is in the style of attributename=”attributevalue”, then it will store the name and value in the xmlAttribute to return back to the calling method.

/*xmlReader*/
xmlReader::xmlReader()
{
}
 
// attribute is normally in the format of attributeName="attributeValue"
xmlAttribute xmlReader::getAttribute(string attributeString)
{
  xmlAttribute returnAttribute;
 
  // make sure that there is a = in the attribute string
  int findEqual = attributeString.find('=');
  if (findEqual > 0)
  {
    // set the attribute name to the substring till the equal
    returnAttribute._attributeName = attributeString.substr(0,findEqual);
    // make sure that there is some characters after the '=' sign.
    if (attributeString.length() > (findEqual+3))
    {
      returnAttribute._attributeValue = attributeString.substr(findEqual+2,(attributeString.length() - (findEqual +3)));
    }
    else
      throw BADATTRIBUTE;
  }else
    // if there does not appear to be ="" at the end of the string then throw a error.
    throw BADATTRIBUTE;
 
  return returnAttribute;
}

The getAttributesFromString if there are 0-x amount of attributes within a string it will process each one in turn and request the above method getAttributes to actually fill in the xmlAttribute variable.

vector<xmlAttribute> xmlReader::getAttributesFromString(string str)
{
    vector<xmlAttribute> returnAtt;
    xmlAttribute attribute;
    int args;
    char st1[CHARACTERLENGHT];
 
    // args normally equals 1 because there is a attribute present
    // else there was no attribute there, just do one at a time
    args = sscanf(str.c_str(), "%s", st1);
    while (args  == 1 && (str.length() > 1)) {
      // see if there is a real attribute attributeName="attributeValue"
      try {
	attribute = getAttribute(st1);
	// push back in the vector array the attribute
	returnAtt.push_back(attribute);
      } catch (string errorStr)		// any errors
      {
	cout << "ERROR : " << errorStr << endl;
      }
      // re-do the string to pull out any more attributes.
      str = str.substr(strlen(st1));
      // see if there is any more attributes present.
      args = sscanf(str.c_str(), "%s", st1);
    }
    return returnAtt;
}

readLine, is the main part of the xml reading object. Here is the basics of what this class is doing.

If there is no tagname within a xml line, return.

If the xml line is the main definition process that style of xml line input, and pull out any attributes that are present.

Else process a normal xml line input with attributes (if present) get the value of the tag and then check to make sure that the end tag name is the same as the first tagname.

// scan through the xml string and pull out the tags and the attributes and value.
xmlObject xmlReader::readLine(string xmlToSplitUp, string* tagName)
{
  xmlObject returnObj;
  string returnLine, value, endTagName;
  int findXml;
 
  // pick out the tag name, if none then return and throw a bad tag name error.
  *tagName = readUntilCharacter(xmlToSplitUp, '<','>', &returnLine);
  if (tagName->length() ==0)
  {
     throw BADTAGNAME;
     return returnObj;
  }
 
  // if there is a xml version etc in the tagname then process the xml version encoding values.
  findXml=tagName->find("xml");
  if ((findXml > 0 && findXml < tagName->length()) && tagName->length() > 1 )
  {
    // this is the xml version etc.
    // there should be ? at each end of the xml version statement
    string xmlStr = readUntilCharacter(*tagName, '?','?', &returnLine);
    if (returnLine != "?") 
    {
      throw BADXMLVERSION;
      return returnObj;
    }
    // go passed the xml characters.
    returnLine = xmlStr.substr(findXml+3);
    // read any of the attributes from the string
    returnObj.setAttributeVector(getAttributesFromString(returnLine));
    // I am storing the version and any other xml details, so set the return value to store in the correct place.
    returnObj.setXmlMainDetails(true);
  }else if (tagName->length() > 1) 
  {
    // need to see if there is any attributes
    int findTagAtts = tagName->find(' ');
    if (findTagAtts < tagName->length())
    {
      // the attributes are passed the space character in the tagName variable
      string attributes = tagName->substr(findTagAtts);
      // store only the tagName in the tagName variable since pulled out the attributes
      *tagName = tagName->substr(0,findTagAtts);
      // get the attributes into a vector and store in the return object
      returnObj.setAttributeVector(getAttributesFromString(attributes));
    }
 
    if (returnLine.length() > 1)
    {
      // pull out the value in the xml line <tagname>VALUE</tagname>
      value = readUntilCharacter(returnLine,'>','<',&returnLine);
      returnObj.setTagValue(value);
    }
    if (returnLine.length() > 1)
    {
      // pick out the end tag name and make sure it is the same as the first one.
      endTagName = readUntilCharacter(returnLine,'<','>',&returnLine);
      string compareEndTag = "/"+*tagName;
      //if the end tag is not the same as the tag name then throw a error.
      if (endTagName != compareEndTag) 
      {
	throw BADXMLTAGEND;
      } 
    }
    returnObj.setTagName(*tagName);
 
   }
  return returnObj;
}

readUntilCharacter, is to pick out a string between two character points e.g. string = “a place to run to, here is it, codingfriends.com” and you want to pick out “here is it” there is two ‘,’ each side of it. So to pull out the readUntilCharacter(“a place to run to, here is it, codingfriends.com”, ‘,’ , ‘,’ , &returnLine) the returnLine is the rest of the line after the last character searched for.

// pick out the characters between two character points, and also return the rest of the line.
string xmlReader::readUntilCharacter(string line, char characterStart, char characterEnd, string *returnLine)
{
  string returnString;
  // find the first occurrence of the character integer placement
  int firstChar = line.find(characterStart);
  // if there is one.
  if (firstChar >= 0)
  {
    // setup the return string, even if a second part cannot be found.
    returnString = line.substr(firstChar+1, (line.length()- firstChar)-1);
    int secChar = returnString.find(characterEnd);
    //if the secound part can be found
    if (secChar > 0)
    {
      *returnLine = returnString.substr(secChar, (returnString.length() - secChar));
      returnString = returnString.substr(0,secChar);
    }
  }
  return returnString;
}

loadFile will load the xml file into the private _xmlMainDetails and _xmlDetails and just see’s if file is present and try’s to load it.

// read in the XML file and place each line into the vector xmlObject 
bool xmlReader::loadFile(string filename)
{
  xmlObject xmlObj;
  string line, tagName;
 
  ifstream xmlfile(filename.c_str());
  if (xmlfile.is_open())
  {
      // if the xml version and also the encodingvalues are present.    
      while (!xmlfile.eof())
      {
	  // pull out the start tag and compare against the endtag
	  getline(xmlfile,line);
	  try 
	  {
	    // pick out the xml details from line and return a xmlObject 
	    // to add to the vector array of xml objects
	    // also return the tagName if any futher processing is required.
	    xmlObj = readLine(line, &tagName);
	    // if there is ?xml version etc details present store, else store into the main xml details
	    if (xmlObj.getXmlMainDetails())
	    {
	      _xmlMainDetails.push_back(xmlObj);
	    }
	    else
	    {  
	      _xmlDetails.push_back(xmlObj);
	    }
	  }
	  // if any error occur during the reading of the xml line.
	  catch (string errorStr)
	  {
	    cout << "ERROR : " << errorStr << endl;
	  }
      }
 
      xmlfile.close();
  }
  else
  {
      cout << "Unable to open the file" << endl;
  }
}

Will print out the xml loaded from the xml file.

/* print Out the outer XML values */
void xmlReader::printOuterXML()
{
    cout << "XML Reader Main Object (Xml main details) " << endl;
    for (int i =0; i < _xmlMainDetails.size(); i++)
      _xmlMainDetails.at(i).printOutXmlObject();
 
    cout << "XML Reader xml details" << endl;
    for (int i =0; i < _xmlDetails.size(); i++)
      _xmlDetails.at(i).printOutXmlObject();
}

here are the constant string values.

const int CHARACTERLENGHT = 80;
const string BADXMLVERSION = "Xml version - first line ? - problem";
const string BADTAGNAME = "Tag name was not present";
const string BADXMLTAGEND = "End tag is not the same as tag name";
const string BADATTRIBUTE = "Attribute in wrong format attributeName=\"attributeValue\"";

Xml object – c++

From the main project xmlreader, here is the xml object that I created to have a xml line of code which holds the details of a basic xml.

The main basics of a xml are as below

<tagname attributesname="attributesvalue">value</tagname>

So I will need to store the tagname, attributes and the value. Here is the class structure that I did come up with.

class xmlObject {
  private :
    string _tagName, _tagValue;
    vector<xmlAttribute> _attributes;
    bool _xmlMainDetails;
 
  public:
      xmlObject() { _xmlMainDetails = false;} ;
      xmlObject(string tag, string tValue, xmlAttribute attribute);
 
      void setTagName(string tagName);
      void setTagValue(string tagValue);
      void addAttributes(xmlAttribute attribute);
      void setAttributeVector(vector<xmlAttribute> setAtt);
      void setXmlMainDetails(bool value);
      bool getXmlMainDetails();
      void printOutXmlObject();
};

The set/getXmlMainDetails are if the are at the top of the xml file and need to store them in a different place.

A vector is a nice array basically, it allows to dynamically increment the size of the array with using the push_back (and the opposite to shrink pop_back).

The basics of a vector are as below, means to have a vector of type int

vector<int> intvector;

Here is the class implementation of the object structure xmlObject

/* xmlObject */
// constructor for xmlObject, if any details are passed whilst constructing 
xmlObject::xmlObject(string tag, string tValue, xmlAttribute attribute)
{
  _tagName = tag;
  _tagValue = tValue;
  _attributes.push_back(attribute);
}
 
// xml <tagname attributes="attributesvalue">VALUE</tagname>
// set the tag name
void xmlObject::setTagName(string tagName)
{
  _tagName = tagName;
}
 
// set tag value
void xmlObject::setTagValue(string tagValue)
{
  _tagValue = tagValue;
}
 
// add attributes to the vector attributes variable
void xmlObject::addAttributes(xmlAttribute attribute)
{
  _attributes.push_back(attribute);
}
 
// fill in the vector attributes variable.
void xmlObject::setAttributeVector(vector<xmlAttribute> setAtt)
{
  _attributes = setAtt;
}
 
// print out the xml object detais, with the attributes values.
void xmlObject::printOutXmlObject()
{
  cout << "XML Object" << endl;
  cout << "Tagname  :" << _tagName << endl;
  cout << "Tagvalue :" << _tagValue << endl;
  for (int i= 0; i < (int)_attributes.size(); i++)
  {
      cout << "Attribute " << i << " : Name : "<< _attributes.at(i)._attributeName << " Value : " << _attributes.at(i)._attributeValue << endl;
  }
}
 
// set the main set details value
void xmlObject::setXmlMainDetails(bool value)
{	
    _xmlMainDetails = value;
}
 
// get a boolean value to see if the xmlObject is the main <?xml .. ?> value
bool xmlObject::getXmlMainDetails()
{
  return _xmlMainDetails;
}

I shall post on how to implement/compile etc a class in two different files later on, in a lessons basics for different languages but on the whole, if you store the top structure in a .h header file and then the implementation in a .cpp file. Of course shall post the whole code to store in .h .cpp files accordlying for the whole project but this is just a stripped down version.

Xml Attributes – c++

I am doing the project xml reader in cpp and here is the start. The main project is xmlreader which will have links to the 3 different parts of the xml reader object that I have created.

The basics of xml are

<tagname attributesName="attributesValue">value</tagname>

there can be 0-n amount of attributes in the XML.

So to start with I have created a basic structure for a xmlAttribute and here it is

struct xmlAttribute {
    string _attributeName, _attributeValue;
};

a structure is a very basic object that has x amount of parts to it.

The next is a xml object that will have 0-x amount of xmlAttributes, there should be a link at the top right to the next xml object class.

BAR 15 – BAR 1 – no parent – nvidia graphics card does not work

I have come up with a fix for the problem that I was having regarding upgrading my 2GB of RAM to 4GB of RAM, when the nvidia was trying to place its memory request into the new system RAM place, as described in more detail here.

This was the error that I was getting, where the BAR 1 for pci 0000:01:00.0 means the nvidia geforce 7600 256MB graphics card.

[    0.397452] pci 0000:00:01.0: BAR 15: address space collision on of bridge [0xb0000000-0xbfffffff]
[    0.397452] pci 0000:00:01.0: BAR 15: cant allocate resource start :0xb0000000-0xbfffffff
[    0.397452] pci 0000:01:00.0: BAR 1: no parent found for of device [0xb0000000-0xbfffffff]

Also the problem with trying to apply the nvnews fix, which meant just blocking out the 0xc0000000-0xd0000000 range was that there was other devices using that and thus they was gaining that memory range before the nvidia could try to access it. What I have done is to hard code (shall try and do a better fix next), so that if anything tries to gain the memory resource 0xc0000000-0xcfffffff it will block the request and they will re-assign the memory in a later process (great linux kernel there 🙂 ). Then if there is a request for the ranges 0xb0000000 – 0xbfffffff (which is where the ACER BIOS tries to say to put the memory for the nvidia graphics card), move that to the 0xc0000000-0xcfffffff. I have placed at the bottom how the memory is organized before and after the update, where the pci devices that was in the 0xc0 -0xcf ranges are now placed further down in the memory allocation table.

So what I have done is to alter the linux-kernel-source-code /arch/x86/pci/i386.c file, by adding into the function pcibios_allocate_bus_resources come code. I have included the full code for the function below and also just the bit that I have updated further down, it is the bit just after the /* Ian Porter */ 🙂

static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
{                                                                            
        struct pci_bus *bus;                                                 
        struct pci_dev *dev;                                                 
        int idx;                                                             
        struct resource *r;                                                  
 
        /* Depth-First Search on bus tree */
        list_for_each_entry(bus, bus_list, node) {
                if ((dev = bus->self)) {          
                        for (idx = PCI_BRIDGE_RESOURCES;
                            idx < PCI_NUM_RESOURCES; idx++) {
                                r = &dev->resource[idx];     
 
 
/*
Ian Porter added, to test for the nvidia problem
 
[0xb0000000-0xbfffffff] is where the BIOS is telling nvidia to get the memory,
but with 4GB this is where the system memory is.                              
 
a better way of doing this, would be to run the BIOS find memory process twice
and then if no resources can gain memory, e.g. nvidia in this case, flag it for the
second run to then give that the starting area and re-do the rest of them, because 
mainly it is the graphics card that needs the most memory..e.g. 256-512 etc.       
*/                                                                                 
                                if ((r->start >= 0xc0000000) && (r->end <= 0xcfffffff)) {
                                        dev_info(&dev->dev,                              
                                                 " not allocating resource 0xc - 0xcf %pR\n",
                                                 r);                                         
                                        /*                                                   
                                                stop any resources gaining the 0xc0000000 - 0xcfffffff
                                                region, the linux kernel will re-place them.          
                                        */                                                            
                                        r->flags = 0;                                                 
                                }                                                                     
 
                                /* where the nvidia is going and replace in the above region */
                                if ((r->start == 0xb0000000) && (r->end == 0xbfffffff)) {      
                                        r->start = 0xc0000000;                                 
                                        r->end = 0xcfffffff;                                   
                                }                                                              
/* stop insert */
 
                                if (!r->flags)
                                        continue;
                                if (!r->start || 
                                    pci_claim_resource(dev, idx) < 0) {
                                        dev_warn(&dev->dev, "BAR %d: can't allocate resource\n", idx);
                                        /*                                                            
                                         * Something is wrong with the region.                        
                                         * Invalidate the resource to prevent                         
                                         * child resource allocations in this                         
                                         * range.                                                     
                                         */                                                           
                                        r->flags = 0;                                                 
                                }                                                                     
                        }                                                                             
                }                                                                                     
                pcibios_allocate_bus_resources(&bus->children);                                       
        }                                                                                             
}

Basically just place this code

/*
Ian Porter added, to test for the nvidia problem
 
[0xb0000000-0xbfffffff] is where the BIOS is telling nvidia to get the memory,
but with 4GB this is where the system memory is.                              
 
a better way of doing this, would be to run the BIOS find memory process twice
and then if no resources can gain memory, e.g. nvidia in this case, flag it for the
second run to then give that the starting area and re-do the rest of them, because 
mainly it is the graphics card that needs the most memory..e.g. 256-512 etc.       
*/                                                                                 
                                if ((r->start >= 0xc0000000) && (r->end <= 0xcfffffff)) {
                                        dev_info(&dev->dev,                              
                                                 " not allocating resource 0xc - 0xcf %pR\n",
                                                 r);                                         
                                        /*                                                   
                                                stop any resources gaining the 0xc0000000 - 0xcfffffff
                                                region, the linux kernel will re-place them.          
                                        */                                                            
                                        r->flags = 0;                                                 
                                }                                                                     
 
                                /* where the nvidia is going and replace in the above region */
                                if ((r->start == 0xb0000000) && (r->end == 0xbfffffff)) {      
                                        r->start = 0xc0000000;                                 
                                        r->end = 0xcfffffff;                                   
                                }

after the

  r = &dev->resource[idx];

in the for loop

compile up the kernel as on this post, the basics are

cd /usr/src/
apt-get install fakeroot kernel-wedge build-essential makedumpfile
 
apt-get build-dep linux
 
apt-get build-dep linux-image-$(uname -r)
apt-get source linux-image-$(uname -r)
 
debian/rules updateconfigs
 
cd debian.master/scripts/misc 
chmod a+x *
cd -
debian/rules updateconfigs

make the changes as described in the file arch/x86/pci/i386.c as above, and then

fakeroot debian/rules clean
CONCURRENCY_LEVEL=2 AUTOBUILD=1 NOEXTRAS=1 fakeroot debian/rules binary-generic

this will create a linux image and headers debian file, after a long wait in the /usr/src directory there will be couple of deb files (Of course change the files names for the header and image that you may have)

cd ..
dpkg -i  linux-headers-2.6.31-17-generic_2.6.31-17.54_amd64.deb
dpkg -i linux-image-2.6.31-17-generic_2.6.31-17.54_amd64.deb

To stop the aptitude from trying to update the linux-image back to the stock one I just did (again change to the image and headers that you have)

aptitude hold linux-image-2.6.31-17-generic_2.6.31-17.54_amd64.deb 
aptitude hold  linux-headers-2.6.31-17-generic_2.6.31-17.54_amd64.deb

Also had to do

echo linux-headers-2.6.31-17-generic hold | dpkg --set-selections
echo linux-image-2.6.31-17-generic hold | dpkg --set-selections

To stop the apt-get upgrade/update as well.

IOMEM of a none working 4GB graphics card, if you note that there is not enough chunck of memory to house the nvidia 256MB memory grab, but there is space enough if the items between the 0xc0000000 – 0xcfffffff are moved about then there is enough space.

00000000-00000fff : System RAM         
00001000-00005fff : reserved           
00006000-0009b3ff : System RAM         
0009b400-0009ffff : reserved           
000dc000-000dffff : reserved           
000e4000-000fffff : reserved           
00100000-bfe8ffff : System RAM         
  01000000-01530dd8 : Kernel code      
  01530dd9-018236af : Kernel data      
  018d5000-019e4ccb : Kernel bss       
  02000000-09ffffff : Crash kernel     
bfe90000-bfe99fff : ACPI Non-volatile Storage
bfe9a000-bfffffff : reserved                 
c0000000-c1ffffff : PCI Bus 0000:03          
c2000000-c3ffffff : PCI Bus 0000:05          
c4000000-c5ffffff : PCI Bus 0000:02          
  c4000000-c401ffff : 0000:02:00.0           
c6000000-c7ffffff : PCI Bus 0000:07          
c8000000-c9ffffff : PCI Bus 0000:03          
ca000000-cbffffff : PCI Bus 0000:05          
cc000000-cdffffff : PCI Bus 0000:02          
  cc000000-cc003fff : 0000:02:00.0           
    cc000000-cc003fff : sky2                 
ce000000-cfffffff : PCI Bus 0000:07          
  ce000000-ce000fff : 0000:07:00.0           
    ce000000-ce000fff : iwl3945              
d0000000-d1ffffff : PCI Bus 0000:01
  d0000000-d0ffffff : 0000:01:00.0
  d1000000-d1ffffff : 0000:01:00.0
d2000000-d20fffff : PCI Bus 0000:09
  d2000000-d2003fff : 0000:09:06.1
  d2004000-d2004fff : 0000:09:06.2
    d2004000-d2004fff : tifm_7xx1
  d2005000-d20057ff : 0000:09:04.0
    d2005000-d20057ff : saa7133[0]
  d2005800-d2005fff : 0000:09:06.1
    d2005800-d2005fff : ohci1394
  d2006000-d20060ff : 0000:09:06.3
    d2006000-d20060ff : mmc0
  d2007000-d2007fff : 0000:09:06.0
    d2007000-d2007fff : yenta_socket
d2300000-d2303fff : 0000:00:1b.0
  d2300000-d2303fff : ICH HD audio
d2304000-d23043ff : 0000:00:1d.7
  d2304000-d23043ff : ehci_hcd
d2304400-d23047ff : 0000:00:1f.2
  d2304400-d23047ff : ahci
d4000000-d7ffffff : PCI Bus 0000:09
  d4000000-d7ffffff : PCI CardBus 0000:0a
d8000000-dbffffff : PCI CardBus 0000:0a
e0000000-efffffff : PCI MMCONFIG 0 [00-ff]
  e0000000-efffffff : reserved
    e0000000-efffffff : pnp 00:01
fec00000-fec0ffff : reserved
  fec00000-fec00fff : IOAPIC 0
fed00000-fed003ff : HPET 0
  fed00000-fed003ff : reserved
fed14000-fed19fff : reserved
  fed14000-fed17fff : pnp 00:01
  fed18000-fed18fff : pnp 00:01
  fed19000-fed19fff : pnp 00:01
fed1c000-fed8ffff : reserved
  fed1c000-fed1ffff : pnp 00:01
  fed20000-fed3ffff : pnp 00:01
  fed45000-fed8ffff : pnp 00:01
fee00000-fee00fff : Local APIC
  fee00000-fee00fff : reserved
ff000000-ffffffff : reserved

Working IOMEM 4GB graphics nvidia geforce 7600 256MB card, the items that was in the 0xc0000000 – 0xcfffffff ranges are now placed further down in the memory allocations, if you look for sky2 , iwl3945 , which are kinder needed for the wireless capabilities of the laptop.

00000000-00000fff : System RAM               
00001000-00005fff : reserved                 
00006000-0009b3ff : System RAM               
0009b400-0009ffff : reserved                 
000dc000-000dffff : reserved                 
000e4000-000fffff : reserved                 
00100000-bfe8ffff : System RAM               
  01000000-01530f79 : Kernel code            
  01530f7a-018216ef : Kernel data            
  018d3000-019e2ccb : Kernel bss             
  02000000-09ffffff : Crash kernel           
bfe90000-bfe99fff : ACPI Non-volatile Storage
bfe9a000-bfffffff : reserved                 
c0000000-cfffffff : PCI Bus 0000:01          
  c0000000-cfffffff : 0000:01:00.0           
d0000000-d1ffffff : PCI Bus 0000:01          
  d0000000-d0ffffff : 0000:01:00.0           
  d1000000-d1ffffff : 0000:01:00.0           
    d1000000-d1ffffff : nvidia               
d2000000-d20fffff : PCI Bus 0000:09          
  d2000000-d2003fff : 0000:09:06.1           
  d2004000-d2004fff : 0000:09:06.2           
    d2004000-d2004fff : tifm_7xx1            
  d2005000-d20057ff : 0000:09:04.0           
    d2005000-d20057ff : saa7133[0]
  d2005800-d2005fff : 0000:09:06.1
    d2005800-d2005fff : ohci1394
  d2006000-d20060ff : 0000:09:06.3
    d2006000-d20060ff : mmc0
  d2007000-d2007fff : 0000:09:06.0
    d2007000-d2007fff : yenta_socket
d2100000-d21fffff : PCI Bus 0000:02
  d2100000-d2103fff : 0000:02:00.0
    d2100000-d2103fff : sky2
d2200000-d22fffff : PCI Bus 0000:02
  d2200000-d221ffff : 0000:02:00.0
d2300000-d2303fff : 0000:00:1b.0
  d2300000-d2303fff : ICH HD audio
d2304000-d23043ff : 0000:00:1d.7
  d2304000-d23043ff : ehci_hcd
d2304400-d23047ff : 0000:00:1f.2
  d2304400-d23047ff : ahci
d2400000-d24fffff : PCI Bus 0000:07
  d2400000-d2400fff : 0000:07:00.0
    d2400000-d2400fff : iwl3945
d4000000-d7ffffff : PCI Bus 0000:09
  d4000000-d7ffffff : PCI CardBus 0000:0a
d8000000-dbffffff : PCI CardBus 0000:0a
e0000000-efffffff : PCI MMCONFIG 0 [00-ff]
  e0000000-efffffff : reserved
    e0000000-efffffff : pnp 00:01
fec00000-fec0ffff : reserved
  fec00000-fec00fff : IOAPIC 0
fed00000-fed003ff : HPET 0
  fed00000-fed003ff : reserved
fed14000-fed19fff : reserved
  fed14000-fed17fff : pnp 00:01
  fed18000-fed18fff : pnp 00:01
  fed19000-fed19fff : pnp 00:01
fed1c000-fed8ffff : reserved
  fed1c000-fed1ffff : pnp 00:01
  fed20000-fed3ffff : pnp 00:01
  fed45000-fed8ffff : pnp 00:01
fee00000-fee00fff : Local APIC
  fee00000-fee00fff : reserved
ff000000-ffffffff : reserved

hope this post helps other people to get around the nvidia laptop memory grab, hopefully I am going to write a pci kernel update so that it does not have to block out a set part of memory.

Multiplication

Whilst I was understanding the bits structure of binary values I did come across the page from here about how to do multiplication with binary values and thought that I might as well do it in c++ to understand abit more about the process.

The main part from that page above is

Rules of Binary Multiplication

  • 0 x 0 = 0
  • 0 x 1 = 0
  • 1 x 0 = 0
  • 1 x 1 = 1, and no carry or borrow bits

For example,

00101001