I am trying to read a .graphml that yEd (yEd) generates. I am able to read simple and manually-generated .graphml files but the yEd files contains several properties to be defined. Does any one has a running example that show how to deal with such yEd files?
The yED file must be filtered to remove all the yEd stuff that boost::read_graphml does not recognize. If all you want is the vertices and edges, this is simple enough. However, if you do want some of the attributes, then it becomes more complex, and will depend on what you need.
Here is some code that filters out all the yED stuff, except the text of the node labels, which is converted to the simplest possible node label attribute that boost::read_graphml can parse and store in a bundled property.
/**
Check for a yEd file
#param[in] n the filename
#return true if the file weas written by yED
The input file is copied to a new file graphex_processed.graphml
If the intput file was NOT produced by yEd, then the copy is perfect
If input was produced by yEd then the copy is filtered so that it can be
read by boost::read_graphml
Most of the yEd stuff is discarded, except for the node labels
the text of which are copied to a simple node attribute "label"
*/
bool cGraph::IsGraphMLbyYED(const std::wstring& n)
{
bool yEd = false;
// open the input file
std::ifstream fin;
fin.open(n.c_str(), std::ifstream::in);
if( ! fin.is_open() ) {
return false;
}
// open the output file
std::ofstream fout;
fout.open("graphex_processed.graphml", std::ifstream::out );
if( ! fout.is_open() ) {
return false;
}
// loop over input file lines
fin.clear();
char buf[1000];
while( fin.good() ) {
fin.getline( buf,999 );
std::string l( buf );
// check for file produced by yEd
if( l.find("<!--Created by yFiles") != -1 ) {
yEd = true;
// convert NodeLabel text to simple label attribute
fout << "<key id=\"key0\" for=\"node\" attr.name=\"label\" attr.type=\"string\" />\n";
}
// check for file already identified as yEd
if( yEd ) {
// filter out yED attributes
if( l.find("<key") != -1 ) {
continue;
}
// convert NodeLabel text
if( l.find("<y:NodeLabel") != -1 ) {
int p = l.find(">")+1;
int q = l.find("<",p);
std::string label = l.substr(p,q-p);
fout << "<data key=\"key0\">" << label << "</data>\n";
continue;
}
// filter out outher yEd stuff
if( l.find("<y:") != -1 ) {
continue;
}
if( l.find("</y:") != -1 ) {
continue;
}
if( l.find("<data") != -1 ) {
continue;
}
if( l.find("</data") != -1 ) {
continue;
}
}
// copy input line to output
fout << buf << std::endl;
}
// close files
fin.close();
fout.close();
// return true if yED file
return yEd;
}
Here is some code to read the filtered file
void cGraph::ReadGraphML(const std::wstring& n)
{
// check if file was produced by yEd
IsGraphMLbyYED( n );
boost::dynamic_properties dp;
dp.property("label", boost::get(&cVertex::myName, myGraph));
myGraph.clear();
std::ifstream fin;
fin.open("graphex_processed.graphml", std::ifstream::in);
if( ! fin.is_open() ) {
return;
}
boost::read_graphml( fin, myGraph, dp );
}
If you want to see an example of this running in an application, take a look at Graphex, a GUI for the BGL, which can read yEd files using this code.
Try this workaround:
https://stackoverflow.com/a/55807107/4761831
I just inherited a class and removed some codes that cause the exception.
Related
I have a CO2 sensor on my Arduino Mega and sometimes randomly when I'm reading the CO2 measurement, the sensor will return a "?". The question mark causes my program to crash and return "input string was not in a correct format".
I haven't tried anything because I don't know what approach would be the best for this. The CO2 sensor returns the measurement in the form of "Z 00000" but when this question mark appears it shows that all that returned was a "\n". Currently, I have the program just reading the 5 digits after the Z.
if (returnString != "")
{
val = Convert.ToDouble(returnString.Substring(returnString.LastIndexOf('Z')+ 1));
}
What I expect to return is the digits after Z which works but every so often I will get a random line return which crashes everything.
According to the C# documentation the ToDouble method throws FormatException whenever the input string is invalid. You should catch the exception to avoid further issues.
try {
val = Convert.ToDouble(returnString.Substring(returnString.LastIndexOf('Z')+ 1));
}
catch(FormatException e) {
//If you want to do anything in case of an error
//Otherwise you can leave it blank
}
Also I'd recommend using some sort of statemachine for parsing the data in your case, that could discard all invalid characters. Something like this:
bool z_received = false;
int digits = 0;
int value = 0;
//Called whenever you receive a byte from the serial port
void onCharacter(char input) {
if(input == 'Z') {
z_received = true;
}
else if(z_received && input <= '9' && input >= '0') {
value *= 10;
value += (input - '0');
digits++;
if(digits == 5) {
onData(value);
value = 0;
z_received = false;
digits = 0;
}
}
else {
value = 0;
z_received = false;
digits = 0;
}
}
void onData(int data) {
//do something with the data
}
This is just a mock-up, should work in your case if you can direct the COM port's byte stream into the onCharacter function.
ALL,
for( std::map<int, std::vector<Foo *> >::iterator it = fkFields.begin(); it != fkFields.end() && !found; it++ )
{
for( std::vector<Foo *>::iterator it1 = it->second.begin(); it1 < it->second.end(); ++it1 )
{
if( refTableOrig == (*it1)->GetReferencedTableName() )
{
found = true;
delete (*it1);
(*it1) = NULL;
it->second.erase( it1 );
}
}
if( found )
fkFields.erase( it );
}
This code above is crashing when there is only 1 element in the std::vector because the code will try to go over the iterator::end().
Also I can't just vector.erase()/vector.remove() because the vector contains pointers and the memory has to be deleted.
So what is the proper way to delete the pointer to the element from the vector.
P.S.: This is different from all other questions since my vector holds pointers and not objects.
TIA!!
Firstly, you should check it1 != it->second.end().
Secondly, what is the return value of vector::erase ?
An iterator pointing to the new location of the element that followed the last element erased by the function call.
so you should use this information and rewrite your inner for loop as follows
for( std::vector<Foo *>::iterator it1 = it->second.begin(); it1 != it->second.end(); )
// [1] changed it1 != it->second.end() [2] removed ++it1
{
if( refTableOrig == (*it1)->GetReferencedTableName() )
{
found = true;
delete (*it1);
(*it1) = NULL;
it1 = it->second.erase( it1 );
}
else
++it1;
}
I have a program that reads from a .txt file
I use the cmd prompt to execute the program with the name of the text file to read from.
ex: program.exe myfile.txt
The problem is that sometimes it works, sometimes it doesn't.
The original file is 130KB and doesn't work.
If I copy/paste the contents, the file is 65KB and works.
If I copy/paste the file and rename it, it's 130KB and doesn't work.
Any ideas?
After more testing it shows that this is what makes it not work:
int main(int argc, char *argv[])
{
char *infile1
char tmp[1024] = { 0x0 };
FILE *in;
for (i = 1; i < argc; i++) /* Skip argv[0] (program name). */
{
if (strcmp(argv[i], "-sec") == 0) /* Process optional arguments. */
{
opt = 1; /* This is used as a boolean value. */
/*
* The last argument is argv[argc-1]. Make sure there are
* enough arguments.
*/
if (i + 1 <= argc - 1) /* There are enough arguments in argv. */
{
/*
* Increment 'i' twice so that you don't check these
* arguments the next time through the loop.
*/
i++;
optarg1 = atoi(argv[i]); /* Convert string to int. */
}
}
else /* not -sec */
{
if (infile1 == NULL) {
infile1 = argv[i];
}
else {
if (outfile == NULL) {
outfile = argv[i];
}
}
}
}
in = fopen(infile1, "r");
if (in == NULL)
{
fprintf(stderr, "Unable to open file %s: %s\n", infile1, strerror(errno));
exit(1);
}
while (fgets(tmp, sizeof(tmp), in) != 0)
{
fprintf(stderr, "string is %s.", tmp);
//Rest of code
}
}
Whether it works or not, the code inside the while loop gets executed.
When it works tmp actually has a value.
When it doesn't work tmp has no value.
EDIT:
Thanks to sneftel, we know what the problem is,
For me to use fgetws() instead of fgets(), I need tmp to be a wchar_t* instead of a char*.
Type casting seems to not work.
I tried changing the declaration of tmp to
wchar_t tmp[1024] = { 0x0 };
but I realized that tmp is a parameter in strtok() used elsewhere in my code.
I here is what I tried in that function:
//tmp is passed as the first parameter in parse()
void parse(wchar_t *record, char *delim, char arr[][MAXFLDSIZE], int *fldcnt)
{
if (*record != NULL)
{
char*p = strtok((char*)record, delim);
int fld = 0;
while (p) {
strcpy(arr[fld], p);
fld++;
p = strtok('\0', delim);
}
*fldcnt = fld;
}
else
{
fprintf(stderr, "string is null");
}
}
But typecasting to char* in strtok doesn't work either.
Now I'm looking for a way to just convert the file from UTF-16 to UTF-8 so tmp can be of type char*
I found this which looks like it can be useful but in the example it uses input from the user as UTF-16, how can that input be taken from the file instead?
http://www.cplusplus.com/reference/locale/codecvt/out/
It sounds an awful lot like the original file is UTF-16 encoded. When you copy/paste it in your text editor, you then save the result out as a new (default encoding) (ASCII or UTF-8) text file. Since a single character takes 2 bytes in a UTF-16-encode file but only 1 byte in a UTF-8-encoded file, that results in the file size being roughly halved when you save it out.
UTF-16 is fine, but you'll need to use Unicode-aware functions (that is, not fgets) to work with it. If you don't want to deal with all that Unicode jazz right now, and you don't actually have any non-ASCII characters to deal with in the file, just do the manual conversion (either with your copy/paste or with a command-line utility) before running your program.
Please correct the below code:only.
file already contains entries : 1st row username; 2nd row password.
checkbox status required to write to the third line and need to read or alter only the checkbox status value in the file.
Currently this code is working if there already is a value for the checkbox status value, then it is overwriting, else UI is hanging.
WriteCheckStatusToFile(BOOL& locVar)
{
FILE *l_pFile = NULL;
CString l_strRememberCheck;
l_strRememberCheck = GetExePath() + _T("password");
CString sVar;
sVar.Format(_T("%d"),locVar);
if(NULL != (l_pFile = fopen(l_strRememberCheck, _T("r+"))) )
{
int count = 0;
char c;
while(count != 2)
{
if((c = fgetc(l_pFile)) == '\n') count++;
}
fseek(l_pFile,ftell(l_pFile),SEEK_SET);
fprintf(l_pFile, sVar);
}
l_strRememberCheck.ReleaseBuffer();
fclose(l_pFile);
}
thanks in advance to all!
sam.
This line
fprintf(l_pFile, sVar);
doesn't look right. I think it should be
fprintf(l_pFile, "%s\n", (LPCTSTR) sVar);
The loop could become infinite if the file has less than two linefeeds:
while(count != 2)
I think it should be:
while( (count < 2) && ( ! feof(l_pFile) ) && ( c != EOF ) )
Probably unrelated to your error, but - at least for this code snippet - CString::ReleaseBuffer() doesn't need to be called since you have not called CString::GetBuffer().
l_strRememberCheck.ReleaseBuffer();
This line may be unnecessary as it appears to fseek() to where the file pointer already is:
fseek(l_pFile,ftell(l_pFile),SEEK_SET);
In the event a two-line file is not terminated with a '\n' you would need to print like this:
if ( count == 2 )
{
fprintf(l_pFile, "%s\n", (LPCTSTR) sVar);
}
else
{
fprintf(l_pFile, "\n%s\n", (LPCTSTR) sVar);
}
I'm trying to deflate and inflate a text file using zlib-1.2.7 with VC++2010.
I used pipe.c as basis and rewrote the main() in order to set the input/output files.
I'm able to deflate any text file but i can't inflate large files without getting a Z_DATA_ERROR (-3).
the inf() and def() are not changed from pipe.c.
Here is my main() :
int main (){
FILE *a, *b, *c;
int ret;
//ZIP
a = fopen("a_data.txt", "r");
b = fopen("b_compressedData.zip", "w");
if(a != NULL && b != NULL){
ret = def(a, b, Z_DEFAULT_COMPRESSION);
printf("%d\n", ret);
if (ret != Z_OK) zerr(ret);
fclose(a);
fclose(b);
}
//UNZIP
b = fopen("b_compressedData.zip", "r");
c = fopen("c_uncompressedData.txt", "w");
if(c != NULL && b != NULL){
ret = inf(b, c);
printf("%d\n", ret);
if (ret != Z_OK) zerr(ret);
fclose(b);
fclose(c);
}
return 0;
}
Here is the inf() function :
int inf(FILE *source, FILE *dest)
{
int ret;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
if (strm.avail_in == 0)
break;
strm.next_in = in;
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END);
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
You need to add a "b" in the modes for fopen(), where the b is for binary. E.g. "rb" and "wb". Otherwise on Windows you get end-of-line conversions which mess up binary data.
By the way, you should not call the compressed file .zip since it isn't. zlib writes zlib-formatted data, or if requested gzip-formatted data. zlib does not write zip-formatted data on its own. There is third-party code for writing zip files, such as in the contrib directory of the zlib source distribution, or in libzip.
I use .zz as the suffix for zlib-formatted data. .gz is the suffix for gzip-formatted data.