I am playing with TagLib (on Windows, built with MingW). I am trying to get TagLib to recognize when there is no ID3v1 or ID3v2 information in an MP3 file. According to the TagLib documentation, the ID3v2Tag() function in an MPEG File object should return a NULL pointer when there is no ID3v2 information in the file.
Unfortunately, this is not occurring. I have some test MP3 files I have made that I use in my code (I have made the files available):
blank.mp3 (download), no ID3v1 or ID3v2 information at all. I can confirm this by doing a plain text search for "TAG" and "ID3" in the files binary content.
only_album_id3v2.mp3 (download), has ID3v2 information (only the album is set)
only_album_id3v1.mp3 (download), has ID3v1 information (only the album is set)
Here is my code.
#include <iostream>
#include <mpeg/mpegfile.h>
#include <mpeg/id3v2/id3v2tag.h>
using namespace std;
int main()
{
cout << "Test." << endl;
TagLib::MPEG::File a("tests/other/blank.mp3");
TagLib::MPEG::File b("tests/id3v2/only_album_id3v2.mp3");
TagLib::MPEG::File c("tests/id3v1/only_album_id3v1.mp3");
TagLib::ID3v2::Tag * at = a.ID3v2Tag();
TagLib::ID3v2::Tag * bt = b.ID3v2Tag();
TagLib::ID3v2::Tag * ct = c.ID3v2Tag();
cout << at->album() << endl;
cout << bt->album() << endl;
cout << ct->album() << endl;
cout << "The program is done.";
return 0;
}
Running this program should break, due to a NULL pointer error on cout << at->album() << endl;, but it runs just fine. Also, when I cout << ct << endl;, it returns a memory address.
Here is the output:
Test.
test album id3v2
The program is done.
EDIT:
Here is a new test.
#include <iostream>
#include <mpeg/mpegfile.h>
#include <mpeg/id3v2/id3v2tag.h>
using namespace std;
int main()
{
cout << "Test." << endl;
TagLib::MPEG::File a("tests/other/blank.mp3");
TagLib::MPEG::File b("tests/id3v2/only_album_id3v2.mp3");
TagLib::MPEG::File c("tests/id3v1/only_album_id3v1.mp3");
TagLib::ID3v2::Tag * at = a.ID3v2Tag();
TagLib::ID3v2::Tag * bt = b.ID3v2Tag();
TagLib::ID3v2::Tag * ct = c.ID3v2Tag();
if(at == NULL)
{
cout << "at is NULL.";
}
else
{
cout << "at is not NULL.";
}
cout << endl;
if(bt == NULL)
{
cout << "bt is NULL.";
}
else
{
cout << "bt is not NULL.";
}
cout << endl;
if(ct == NULL)
{
cout << "ct is NULL.";
}
else
{
cout << "ct is not NULL.";
}
cout << endl;
cout << "The program is done.";
return 0;
}
And here is the output.
Test.
at is not NULL.
bt is not NULL.
ct is not NULL.
The program is done.
I examined TagLib's code briefly.
I know nothing about it and never used it, but the code looks buggy to me. Here's why -
In MPEG::File::read(), we are looking for a tag - d->ID3v2Location = findID3v2();. If it doesn't exist, it isn't added to the tags vector. This is the check - if(d->ID3v2Location >= 0).
However, at the end of the function, just before returning, we have -
// Make sure that we have our default tag types available.
ID3v2Tag(true);
ID3v1Tag(true);
Now, Id3v2Tag(create) with a true parameter, actually calls return d->tag.access(ID3v2Index, create);. The access() function is -
template <class T> T *access(int index, bool create)
{
if(!create || tag(index))
return static_cast<T *>(tag(index));
set(index, new T);
return static_cast<T *>(tag(index));
}
So when create is true, we are creating a brand new, empty tag and placing it in the vector (using the set() function).
This means that no matter whether the file contains the tags or not, they are added to the vector. This isn't the documented behavior. Looks like a bug.
I don't know why these two lines are needed there - looking at the history of this file might hint as to why they were added, but I didn't do that.
Anyway, I want to stress that I never actually executed this code. This is based on purely statically reading only very small parts, without being aware of large scale issues.
I think that opening a bug report can't hurt.
Using a null pointer doesn't necessarily result in any error you can see; it's undefined behavior. It might appear to work, or it might do something really really weird.
In this case the compiler is probably generating a call to TagLib::ID3v2::Tag::album with the this pointer set to null, but even this is not guaranteed. What happens inside the function is anyone's guess.
If the function can return NULL, you should be explicitly checking for it and doing something different.
Taglib create an "Empty" ID3v2Tag and ID3v1Tag in the object if the file do not have one.
I am having simmilar problem and hopefully I've found workaround for ID3v1/ID3v2 presence checking.
It's method virtual bool TagLib::Tag::isEmpty() const
Related
Good day,
I have a loop that computes values and displays the output to the console. However, when I run the code, cout << does not display the output I expected. In fact, it doesn't display any output. The only way I know the code even works is that the values are changing.
cout << was working just fine until I used the switch statement. Every piece of text that I expected to print to the console inside the statement and the loop was just dead text. It didn't work. I also tried flushing the stream using cout.flush. That did not work either I cannot include all of my code, but here are the problem lines:
if (exampleloop == '1'){
ExampleValue = (ExampleValue - 1);
ExampleValue = (ExampleValue - ExampleValue);
cout << "ExampleText " << ExampleValue << " ExampleText";
if (ExampleValue <= 0){
cout << "ExampleText.";
}
if (ExampleValue <= 0){
cout << ExampleText";
}
example_label:
ExampleValue = (ExampleValue1 - ExampleValue1);
cout << "ExampleText! " << ExampleValue! << " ExampleText!";
goto Example_label;
}
And the only way I know that the code is being computed
cout << "EXAMPLE TEXT ExampleValue1 at "<< ExampleValue <<" . ExampleText";
In this case, "Example Text" would never appear on the console. However, the "Example Values" would be computed and the changes would reflect on the code above.
My IDE is repl.it
Is this my fault, or my IDE's? And what is going on?
(Yes, I #include iostream and I'm using namespace std)
I'm using this code to output nodes of a huffman tree to a text file with a certain formatting. All the node outputs within the if block run as expected, but the first output in the else block is missing the '0' fill character after the "L:". It should output "L:076" but instead is outputting "L: 76". The cout looks correct but the text file isn't. All future loops through the else block output like they should, it's only the first loop that is missing the fill character. Here's a picture of my output
void preOrder(node* tree, std::ofstream& of) {
if (tree->label > 0) {
of << "I:" << tree->label << " ";
}
else {
std::cout.width(3);
std::cout << std::right;
std::cout.fill('0');
std::cout << int(tree->ch) << std::endl;
of << "L:";
of << of.fill('0');
of << std::right;
of << int(tree->ch);
of << " ";
return;
}
preOrder(tree->left, of);
preOrder(tree->right, of);
}
From cppreference.com:
The second form (2) sets fillch as the new fill character and returns the fill character used before the call.
"The second form" is the non-const version, that applies here. So my guess (I never used fill myself and I cannot compile your code as it is) would be that the call is correctly applied and then you put the old fill character (blank space presumably) to the stream, because you do:
of << of.fill('0');
Also, I noticed that you dont set the width of of.
Because you're hiding something naughty from us.
#include <iostream>
int main()
{
std::cout.width(3);
std::cout << std::right;
std::cout.fill('0');
std::cout << 3 << std::endl;
return 0;
}
Outputs 003 (live example).
Please provide an MCVE and I'll edit my answer to help you.
I'm trying to build a lambda that wraps some input functions with some pre/post actions.
My code works fine and pre/post actions get called correctly if I try to wrap a regular function/lambda.
However, when I try to apply my decorating lambda to a function that it produced before, my program crashes after complaining that the inner function was freed at some point (this is confirmed by valgrind).
What puzzles me is that the crash depends on the compiler: the code works perfectly fine with Xcode 6 clang (clang-3.6 based), but crashes on linux using clang++-3.6 and g++4.8.4.
I've made a small program that reproduces the behaviour:
#include <iostream>
#include <string>
#include <functional>
using namespace std;
typedef function<void(void)> NestedFn;
int main()
{
// Create a cfunction
auto lambdaFactory = [&](string title, NestedFn nestedFunc)
{
// title is copied to the new lambda
return [&, title]() {
cerr << "------------ START -----------" << endl;
cerr << "Inside: " << title << endl;
nestedFunc();
cerr << "------------- END ------------" << endl;
};
}
auto l1 = lambdaFactory("1", []() { cerr << "\tNest (1)" << endl; });
auto l2 = lambdaFactory("2", []() { cerr << "\tNest (2)" << endl; });
l1(); // Works ok, displays, START, 1, END
l2(); // Same here
auto dobble = lambdaFactory("Dobble", l1);
dobble(); // Display START, Inside Dobble, START,
// then crashes when trying to execute nestedFunc(), ie l1()
}
What did I get wrong in the variable scope management ? And is there any reason for this program not crashing using Apple's LLVM ?
EDIT
For the record, here is the correct lambdaFactory after the correction suggested by T.C. :
auto lambdaFactory = [&](string title, NestedFn nestedFunc)
{
return [&, title, nestedFunc]() {
cerr << "------------ START -----------" << endl;
cerr << "Inside: " << title << endl;
nestedFunc();
cerr << "------------- END ------------" << endl;
};
};
The lambda returned by a call to lambdaFactory captures nestedFunc by reference, but nestedFunc is a function argument passed by value, so it goes out of scope as soon as the call to lambdaFactory returns, resulting in a dangling reference.
And is there any reason for this program not crashing using Apple's LLVM ?
Undefined behavior is undefined. You are also likely using two different standard library implementations (libc++ on Mac/libstdc++ on linux), so there are likely differences in how everything is laid out etc.
I'm developing a application and my idea is store "apps" in files, like executables. Now i have that:
AppWriter.c
#include <vector>
#include <time.h>
#include <functional>
struct PROGRAM
{
std::vector<int> RandomStuff;
std::vector<std::function<void()>> Functions;
std::function<void()> MAIN;
} CODED;
void RANDOMFUNC()
{
srand(time(NULL));
for(int i = 0; i < 40; i++)
CODED.RandomStuff.push_back(rand() % 254);
}
void LOGARRAY()
{
for(int i = 0; i < CODED.RandomStuff.size(); i++)
std::cout << "["<< i + 1 <<"]: "<< CODED.RandomStuff[i] << std::endl;
}
void PROGRAMMAIN()
{
std::cout << "Hello i call random function!" << std::endl;
CODED.Functions[0]();
CODED.Functions[1]();
}
void main()
{
CODED.MAIN = PROGRAMMAIN;
CODED.Functions.push_back(RANDOMFUNC);
CODED.Functions.push_back(LOGARRAY);
std::cout << "Testing MAIN" << std::endl;
CODED.MAIN();
FILE *file = fopen("TEST_PROGRAM.TRI","wb+");
fwrite(&CODED,sizeof(CODED),1,file);
fclose(file);
std::cout << "Program writted correctly!" << std::endl;
_sleep(10000);
}
AppReader.c
#include <iostream>
#include <vector>
#include <time.h>
#include <functional>
struct PROGRAM
{
std::vector<int> RandomStuff;
std::vector<std::function<void()>> Functions;
std::function<void()> MAIN;
} DUMPED;
void main()
{
FILE *file = fopen("TEST_PROGRAM.TRI","rb+");
fseek(file,0,SEEK_END);
int program_len = ftell(file);
rewind(file);
fread(&DUMPED,sizeof(PROGRAM),1,file);
std::cout
<< "Function array size: " << DUMPED.Functions.size() << std::endl
<< "Random Stuff Array size: " << DUMPED.RandomStuff.size() << std::endl;
DUMPED.MAIN();
}
When i run AppReader the functions dont work(Maybe why std::function it's like void pointers?), but in arrays or if i add variables i can see with debugger the data are storaged correctly (for that i tryed the vector of functions), but whatever doesn't work throw's me error on functional file. ¿Any ideas how i can do that?
This is never going to work. At all. Ever. std::function is a complex type. Binary reads and writes don't work for complex types. They never can. You would have to ask for functions in a pre-defined serializable format, like LLVM IR.
Your problem is that you're storing information about functions that exist in one executable, then trying to run them in a separate executable. Other than that, your code does work, but as DeadMG says, you shouldn't be storing complex types in a file. Here's how I modified your code to prove that your code works if run within a single executable:
#include <iostream>
#include <vector>
#include <time.h>
#include <functional>
struct PROGRAM
{
std::vector<int> RandomStuff;
std::vector<std::function<void()>> Functions;
std::function<void()> MAIN;
} CODED;
void RANDOMFUNC()
{
srand(time(NULL));
for(int i = 0; i < 40; i++)
CODED.RandomStuff.push_back(rand() % 254);
}
void LOGARRAY()
{
for(int i = 0; i < CODED.RandomStuff.size(); i++)
std::cout << "["<< i + 1 <<"]: "<< CODED.RandomStuff[i] << std::endl;
}
void PROGRAMMAIN()
{
std::cout << "Hello i call random function!" << std::endl;
CODED.Functions[0]();
CODED.Functions[1]();
}
int main()
{
CODED.MAIN = PROGRAMMAIN;
CODED.Functions.push_back(RANDOMFUNC);
CODED.Functions.push_back(LOGARRAY);
std::cout << "Testing MAIN" << std::endl;
CODED.MAIN();
FILE *file = fopen("TEST_PROGRAM.TRI","wb+");
fwrite(&CODED,sizeof(CODED),1,file);
fclose(file);
std::cout << "Program writted correctly!" << std::endl;
// _sleep(10000);
std::cout << "---------------------\n";
file = fopen("TEST_PROGRAM.TRI","rb+");
fseek(file,0,SEEK_END);
int program_len = ftell(file);
rewind(file);
fread(&CODED,sizeof(PROGRAM),1,file);
std::cout
<< "Function array size: " << CODED.Functions.size() << std::endl
<< "Random Stuff Array size: " << CODED.RandomStuff.size() << std::endl;
CODED.MAIN();
}
The problem is not that you're storing complex types via binary read/write, per se. (Although that is a problem, it's not the cause of the problem you posted this question about.) Your problem is that your data structures are storing information about the functions that exist in your 'writer' executable. Those same functions don't even exist in your 'reader' executable, but even if they did, they likely wouldn't be at the same address. Your data structures are storing, via std::function, pointers to the addresses where the functions exist in your 'writer' executable. When you try to call these non-existent functions in your 'reader' executable, your code happily tries to call them but you get a segfault (or whatever error your OS gives) because that's not the start of a valid function in your 'reader' executable.
Now with regard to writing complex types (e.g. std::vector) directly to a file in binary format: Doing so "works" in the sample code above only because the binary copies of the std::vectors have pointers that, once read back in, still point to valid data from the original std::vectors which you wrote out. Note that you didn't write the std::vector's actual data, you only wrote their metadata, which probably includes things like the length of the vector, the amount of memory currently allocated for the vector, and a pointer to the vector's data. When you read that back, the metadata is correct except for one thing: Any pointers in it are pointing to addresses that were valid when you wrote the data, but which may not be valid now. In the case of the sample code above, the pointers end up pointing to the same (still valid) data from the original vectors. But there's still a problem here: You now have more than one std::vector that thinks they own that memory. When one of them is deleted, it will delete the memory that the other vector expects to still exist. And when the other vector is deleted, it will cause a double-delete. That opens the door to all kinds of UB. E.g. that memory could have been allocated for another purpose by that time, and now the 2nd delete will delete that other purpose's memory, or else the memory has NOT been allocated for another purpose and the 2nd delete may corrupt the heap. To fix this, you'd have to serialize out the essence of each vector, rather than their binary representation, and when reading it back in, you'd have to reconstruct an equivalent copy, rather than simply reconstitute a copy from the binary image of the original.
I am trying to write a programme to read MRI data by using VTK and C++. But I can't get spacing of MRI raw data in main.
The "GetSpacing" only works in "ReadImageData" function. I think I made some mistake in C++ programming. But I don't know where it is.
vtkImageData* ReadImageData(string mri_imagedata_file)
{
vtkSmartPointer<vtkMetaImageReader> reader =
vtkSmartPointer<vtkMetaImageReader>::New();
reader->SetFileName(mri_imagedata_file.c_str());
reader->Update();
vtkImageData* metaimage = reader->GetOutput();
double sp[3];
metaimage->GetSpacing(sp);
cout << sp[0] << " " << sp[1] << " " << sp[2] <<endl; //<----------It works here.
return metaimage;
}
int main (int argc, char *argv[])
{
if(argc != 2)
{
cerr << "Usage: " << argv[0] << " MRI image data" <<endl;
return EXIT_FAILURE;
}
string mri_imagedata_file = argv[1];// Input "prost00.mhd"
vtkImageData* metaimage = ReadImageData(mri_imagedata_file);
double sp2[3];
metaimage->GetSpacing(sp2);
cout << sp2[0] << " " << sp2[1] << " " << sp2[2] << endl; //<-----It doesn't work here
}
Thank you for your attention.
Assuming vtkSmartPointer<vtkMetaImageReader> is a kind of smart pointer whatever, reader points to in the function is destructed when ReadImageData returns. That includes what metaimage is pointing to.
return metaimage;
// reader->~(); // Destructed here. Including what is pointed to by metaimage.
}
A good solution would be to return the smart pointer instead of metaimage. That way what is pointed to by reader will not be destructed when ReadImageData returns and will be available in main.
My assumption is that vtkMetaImageReader::GetOutput() returns pointer to some vtkMetaImageReader internal data, so when you exit ReadImageData your reader is destroyed and the pointer you return becomes invalid.
It looks like you forgot to pass the array as a parameter to GetSpacing in main, so it calls the overload that returns a double*, leaving your array untouched.
You're also printing an array called spacing although it looks like you want the spacing in sp2.