I'm currently learning c++ and decided as a first project to make a wave file parser. I have the logic I want to get the ChunkSize, but for some reason the bit shifting for wav.ChunkSize causes the wav.ChunkID to append 2 extra characters at the end.
#include <fstream>
#include <iterator>
#include <vector>
#include <iostream>
#include <bitset>
#include "bwave.h"
#include <cstdint>
using namespace std;
bwave wav;
int main(){
std::ifstream input("cello.wav", std::ios::binary);
std::vector<uint8_t> buffer((std::istreambuf_iterator<char>(input)),(std::istreambuf_iterator<char>()));
for (int i = 0; i < 60 ; ++i)
{
std::cout << "Byte " << i << ": ";
std::cout << buffer[i] <<" ";
std::cout << "\n";
}
wav.ChunkID[0] = buffer[0];
wav.ChunkID[1] = buffer[1];
wav.ChunkID[2] = buffer[2];
wav.ChunkID[3] = buffer[3];
wav.Type[0] = buffer[8];
wav.Type[1] = buffer[9];
wav.Type[2] = buffer[10];
wav.Type[3] = buffer[11];
wav.DataStart[0] = buffer[36];
wav.DataStart[1] = buffer[37];
wav.DataStart[2] = buffer[38];
wav.DataStart[3] = buffer[39];
unsigned char tmp[4];
// ChunkSize
for (int i = 4; i < 8 ; ++i)
{
switch(i){
case 4:
tmp[3] = buffer[i];
std::cout << bitset<8>(tmp[3]) << "\n";
break;
case 5:
tmp[2] = buffer[i];
std::cout << bitset<8>(tmp[2]) << "\n";
break;
case 6:
tmp[1] = buffer[i];
std::cout << bitset<8>(tmp[1]) << "\n";
break;
case 7:
tmp[0] = buffer[i];
std::cout << bitset<8>(tmp[0]) << "\n";
break;
default:
printf("%s\n","Error!" );
break;
}
}
std::cout << bitset<24>(tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3] ) << "\n";
wav.ChunkSize = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
// Datasize
for (int i = 40; i < 44 ; ++i)
{
switch(i){
case 40:
tmp[3] = buffer[i];
break;
case 41:
tmp[2] = buffer[i];
break;
case 42:
tmp[1] = buffer[i];
break;
case 43:
tmp[0] = buffer[i];
break;
default:
printf("%s\n","Error!" );
break;
}
}
//wav.DataSize = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
std::cout << "Header: " << wav.ChunkID << "\n";
std::cout << "Size: " << wav.ChunkSize << "\n";
std::cout << "Type: " << wav.Type << "\n";
std::cout << "Data: " << wav.DataStart << "\n";
std::cout << "Data Size: " << wav.DataSize << "\n";
return 0;
}
Output of the following.
...
Byte 59:
00101010
01100011
00001100
00000000
000011000110001100101010
Header: RIFF*c
Size: 811818
Type: WAVE
Data: data
Data Size:
Also i'm open to any suggestions for best practices.
Reference - http://soundfile.sapp.org/doc/WaveFormat/
Thank you for your time,
B
EDIT - The bwave file
struct bwave{
char ChunkID[4];
uint ChunkSize;
char Type[4];
char Format[4];
uint NumChannels;
uint SampleRate;
uint BPS;
char DataStart[4];
char DataSize;
};
Looks like my problem has been solved! I fixed it by giving my char array 1 extra byte than it needed. I think this worked, because C expects a null terminator and if it doesn't see one the memory does something wonkey. Like printing characters I didn't want.
the fix in the end was as follows.
char ChunkID[4]; -> char ChunkID[5];
Thank you everyone for the help!
Related
I'm trying to create a program that displays output of a bmp file in the form of hexadecimal. So far I get the output, but I need it to be organized a certain way.
The way it needs to be organized is with the address of the bmp file to be on the left column and then 16 bytes of data in hex across each row in the order they appear in the file. While leaving an extra space between every 8 bytes. So far, I got the hexadecimal to show up, I just need help with organizing it.
What I have:
What I'm trying to make it look like:
Here is my code:
#include <iostream> // cout
#include <fstream> // ifstream
#include <iomanip> // setfill, setw
#include <stdlib.h>
using namespace std; // Use this to avoid repeated "std::cout", etc.
int main(int argc, char *argv[]) // argv[1] is the first command-line argument
[enter image description here][1]{
// Open the provided file for reading of binary data
ifstream is("C:\\Users\\Test\\Documents\\SmallTest.bmp", ifstream::binary);
if (is) // if file was opened correctly . . .
{
is.seekg(0, is.end); // Move to the end of the file
int length = is.tellg(); // Find the current position, which is file length
is.seekg(0, is.beg); // Move to the beginning of the file
char * buffer = new char[length]; // Explicit allocation of memory.
cout << "Reading " << length << " characters... ";
is.read(buffer, length); // read data as a block or group (not individually)
if (is)
cout << "all characters read successfully.\n";
else
cout << "error: only " << is.gcount() << " could be read.\n";
is.close();
// Now buffer contains the entire file. The buffer can be printed as if it
// is a _string_, but by definition that kind of print will stop at the first
// occurrence of a zero character, which is the string-ending mark.
cout << "buffer is:\n" << buffer << "\n"; // Print buffer
for (int i = 0; i < 100; i++) // upper range limit is typically length
{
cout << setfill('0') << setw(4) << hex << i << " ";
cout << setfill('0') << setw(2) << hex << (0xff & (int)buffer[i]) << " ";
}
delete[] buffer; // Explicit freeing or de-allocation of memory.
}
else // There was some error opening file. Show message.
{
cout << "\n\n\tUnable to open file " << argv[1] << "\n";
}
return 0;
}
You could do it something like this:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <cctype>
std::ostream& fullLine(std::ostream& out, const std::vector<uint8_t>& v, size_t offset)
{
//save stream state so we can restore it after all the hex/setw/setfill nonsense.
std::ios oldState(0);
oldState.copyfmt(out);
out << std::hex << std::setfill('0') << std::setw(8) << offset << " ";
for (size_t i = 0; i < 16; ++i)
{
if (i == 8) out << " ";
out << std::hex << std::setfill('0') << std::setw(2) << static_cast<uint32_t>(v[i + offset]) << " ";
}
out << " ";
//restore stream state to print normal text
out.copyfmt(oldState);
for (size_t i = 0; i < 16; ++i)
{
out << (std::isprint(v[i + offset]) ? static_cast<char>(v[i + offset]) : '.');
}
out << "\n";
return out;
}
int main()
{
std::vector<uint8_t> data;
std::ifstream f("test.txt", std::ios::binary);
if (f)
{
f.seekg(0, f.end);
data.resize(static_cast<size_t>(f.tellg()));
f.seekg(0, f.beg);
f.read((char*)data.data(), data.size());
const size_t numFullLines = data.size() / 16;
const size_t lastLineLength = data.size() % 16;
for (size_t i = 0; i < numFullLines; ++i)
{
if (!fullLine(std::cout, data, i * 16))
{
std::cerr << "Error during output!\n";
return -1;
}
}
}
return 0;
}
There's probably a fancy way to do it, but I usually go for brute force when I'm looking for particular output using iostreams.
How to handle the partial last line is up to you. :)
Use the % operator to break the line after every 16th count:
cout << hex;
for(int i = 0; i < 100; i++)
{
if(i && (i % 16) == 0)
cout << "\n";
cout << setfill('0') << setw(2) << (buffer[i] & 0xFF) << " ";
}
I need it to be organized a certain way.
In another answer, I submitted this form of dumpByteHex()... perhaps it can help you achieve what you want. (see also https://stackoverflow.com/a/46083427/2785528)
// C++ support function
std::string dumpByteHex (char* startAddr, // reinterpret_cast explicitly
size_t len, // allows to char* from T*
std::string label = "",
int indent = 0)
{
std::stringstream ss;
if(len == 0) {
std::cerr << "\n dumpByteHex() err: data length is 0? " << std::endl << std::dec;
assert(len != 0);
}
// Output description
ss << label << std::flush;
unsigned char* kar = reinterpret_cast<unsigned char*>(startAddr); // signed to unsigned
std::string echo; // holds input chars until eoln
size_t indx;
size_t wSpaceAdded = false;
for (indx = 0; indx < len; indx++)
{
if((indx % 16) == 0)
{
if(indx != 0) // echo is empty the first time through for loop
{
ss << " " << echo << std::endl;
echo.erase();
}
// fields are typically < 8 bytes, so skip when small
if(len > 7) {
if (indent) { ss << std::setw(indent) << " "; }
ss << std::setfill('0') << std::setw(4) << std::hex
<< indx << " " << std::flush;
} // normally show index
}
// hex code
ss << " " << std::setfill('0') << std::setw(2) << std::hex
<< static_cast<int>(kar[indx]) << std::flush;
if((indx % 16) == 7) { ss << " "; wSpaceAdded = true; } // white space for readability
// defer the echo-of-input, capture to echo
if (std::isprint(kar[indx])) { echo += kar[indx]; }
else { echo += '.'; }
}
// finish last line when < 17 characters
if (((indx % 16) != 0) && wSpaceAdded) { ss << " "; indx++; } // when white space added
while ((indx % 16) != 0) { ss << " "; indx++; } // finish line
// the last echo
ss << " " << echo << '\n';
return ss.str();
} // void dumpByteHex()
Output format:
0000 11 22 33 44 55 66 00 00 00 00 77 88 99 aa ."3DUf....w...
I am writing the code which counts the lines in the document and split it into equal pats if the line more than 100. To split I am using string.substr(i, i+adding+ addCount). If i have to slit in three parts: First and third split part is OK, Second part has not only its part but also third part words in it. It looks something like this:
linesize: 331
divider3
0 Output I 110
1 EXPRESSION: Mrs. Bennet and her daughters then departed, and Elizabeth returned instantly to Jane, leaving her own and her
0 I
110I 110 0
was here OST
110 Output I 220
2 (error) EXPRESSION: relations’ behaviour to the remarks of the two ladies and Mr. Darcy; the latter of whom, however, could not be prevailed on to join in their censure of her, in spite of all Miss Bingley’s witticisms on fine eyes
110 I
220I 110 0
was here OST
220 Output I 416
3 EXPRESSION: be prevailed on to join in their censure of her, in spite of all Miss Bingley’s witticisms on fine eyes.
220 I
416I 110 86
was here OST
#include <iostream>
#include <deque>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <future>
#include <map>
#include <fstream>
#include <vector>
using namespace std;
atomic<bool> isReady{false};
mutex mtx;
condition_variable condvar;
map<string, int> mapper;
string line;
vector<string> block;
size_t line_index = 0;
int block_size = 100;
int limit_chars = 100;
int c = 0;
deque<vector<string>> dq;
void Producer() {
std::cout << " Producer " << std::endl;
fstream fl("/home/ostap/CLionProjects/WordsCount2/file.txt"); //full path to the file
if (!fl.is_open()) {
cout << "error reading from file" << endl;
}
else {
cout << "SUCCESS!!!" << endl;
while (getline(fl, line) && line_index < block_size) {
if (line.find_first_not_of(' ') != string::npos) { // Checks whether it is a non-space.
// There's a non-space.
cout<< "linesize: " << line.length() << endl;
if (line.length() / limit_chars > 1.4) {
int divider = (int) (line.length() / limit_chars);
int adding = (int) line.length()/divider;
//попробуй поміняти на while все через addCount
int addCount = 0;
int i = 0;
cout <<"divider" << divider<<endl;
while ( i < line.length()){
while (line[i + adding + addCount] != ' ') {addCount+=1;}
cout << i << " Output I " << i + adding + addCount << endl;
cout << "EXPRESSION: " << line.substr(i, i + adding + addCount) << endl; //to del
block.push_back(line.substr(i, i + adding + addCount));
cout << i << " I" << endl;
i = i + adding + addCount;
cout << i << "I" <<" " <<adding <<" "<< addCount <<endl;
++line_index;
addCount = 0;
cout << "was here OST" << endl;
}
}
else {
++line_index;;
block.push_back(line);
cout << "Line: " << line << endl;
}
if (line_index >= block_size) {
c++;
cout << c << endl;
{
lock_guard<mutex> guard(mtx);
//cout << "Producing message: " << x << " th" << endl;
dq.push_back(block);
}
line_index = 0;
block.clear();
}
condvar.notify_one();
}
cout << "Producer completed" << endl;
isReady = true;
// for (unsigned i = 0; i < block.size(); ++i) cout << ' ' << block[i];
// cout << '\n';
//this_thread::sleep_for(chrono::seconds(1));
}
}
}
void Consumer() {
while (true) {
unique_lock<mutex> lk(mtx);
if (!dq.empty()) {
vector<string> & i = dq.front();
dq.pop_front();
lk.unlock();
cout << "Consuming: " << i.data() << " th" << endl;
} else {
if(isReady){
break;
}
else {
condvar.wait(lk);
cout << "There are no messages remained from producer" << endl;
}
}
cout << "\nConsumer is done" << endl;
}
}
int main() {
//cout << "Hello, World!" << endl;
auto t1 = async(launch::async, Producer);
auto t2 = async(launch::async, Consumer);
//auto t3 = async(launch::async, Consumer);
t1.get();
t2.get();
//t3.get();
return -1;
getMessage method extracts the first letter in each word of input string.
Example:
input = "Find the first letters of this Sentence"
output = FtflotS
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cctype>
using namespace std;
class HiddenMessage {
public:
bool space (char c) {
return isspace(c);
}
bool not_space (char c) {
return !isspace (c);
}
string getMessage(string text) {
string ret;
typedef string::const_iterator iter;
iter i, j;
i = text.begin();
while (i != text.end()) {
i = find_if (i, text.end(), not_space); // error here
j = find_if (i, text.end(), space); // error here
if (i != text.end()) {
ret += *i;
}
i = j;
}
return ret;
}
};
//compiler error:
//error: invalid use of non-static member function
I tried making definitions of space and not_space static and it did
not work.
getMessage is called from the main below:
#include <ctime>
#include <cmath>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;
int main(int argc, char* argv[])
{
if (argc == 1)
{
cout << "Testing HiddenMessage (250.0 points)" << endl << endl;
for (int i = 0; i < 20; i++)
{
ostringstream s; s << argv[0] << " " << i;
int exitCode = system(s.str().c_str());
if (exitCode)
cout << "#" << i << ": Runtime Error" << endl;
}
int T = time(NULL)-1456061889;
double PT = T/60.0, TT = 75.0;
cout.setf(ios::fixed,ios::floatfield);
cout.precision(2);
cout << endl;
cout << "Time : " << T/60 << " minutes " << T%60 << " secs" << endl;
cout << "Score : " << 250.0*(.3+(.7*TT*TT)/(10.0*PT*PT+TT*TT)) << " points" << endl;
}
else
{
int _tc; istringstream(argv[1]) >> _tc;
HiddenMessage _obj;
string _expected, _received;
time_t _start = clock();
switch (_tc)
{
case 0:
{
string text = "compete online design event rating";
_expected = "coder";
_received = _obj.getMessage(text); break;
}
case 1:
{
string text = " c o d e r ";
_expected = "coder";
_received = _obj.getMessage(text); break;
}
case 2:
{
string text = "round elimination during onsite contest";
_expected = "redoc";
_received = _obj.getMessage(text); break;
}
case 3:
{
string text = " ";
_expected = "";
_received = _obj.getMessage(text); break;
}
/*case 4:
{
string text = ;
_expected = ;
_received = _obj.getMessage(text); break;
}*/
/*case 5:
{
string text = ;
_expected = ;
_received = _obj.getMessage(text); break;
}*/
/*case 6:
{
string text = ;
_expected = ;
_received = _obj.getMessage(text); break;
}*/
default: return 0;
}
cout.setf(ios::fixed,ios::floatfield);
cout.precision(2);
double _elapsed = (double)(clock()-_start)/CLOCKS_PER_SEC;
if (_received == _expected)
cout << "#" << _tc << ": Passed (" << _elapsed << " secs)" << endl;
else
{
cout << "#" << _tc << ": Failed (" << _elapsed << " secs)" << endl;
cout << " Expected: " << "\"" << _expected << "\"" << endl;
cout << " Received: " << "\"" << _received << "\"" << endl;
}
}
}
You have two problems.
The first, is you are supplying non-static class member functions (space and not_space) to find_if which expects a function object or pointer. So, declare them static if you want them to remain your class, or make them global by placing them outside the class.
The second, your string text parameter is non-const, but, you are working with a const interator type. begin() and end() calls will return const or non-const iterator depending on the calling object (text in this case) and whether or not it is const qualified. So, declare your text parameter as const.
I'm trying to use WideCharToMultiByte in order to convert std::wstring to utf8 std::string. Here is my code:
const std::wstring & utf16("lorem ipsum"); // input
if (utf16.empty()) {
return "";
}
cout << "wstring -> string, input: , size: " << utf16.size() << endl;
for (size_t i = 0; i < utf16.size(); ++i) {
cout << i << ": " << static_cast<int>(utf16[i]) << endl;
}
for (size_t i = 0; i < utf16.size(); ++i) {
wcout << static_cast<wchar_t>(utf16[i]);
}
cout << endl;
std::string res;
int required_size = 0;
if ((required_size = WideCharToMultiByte(
CP_UTF8,
0,
utf16.c_str(),
utf16.size(),
nullptr,
0,
nullptr,
nullptr
)) == 0) {
throw std::invalid_argument("Cannot convert.");
}
cout << "required size: " << required_size << endl;
res.resize(required_size);
if (WideCharToMultiByte(
CP_UTF8,
0,
utf16.c_str(),
utf16.size(),
&res[0],
res.size(),
nullptr,
nullptr
) == 0) {
throw std::invalid_argument("Cannot convert.");
}
cout << "Result: " << res << ", size: " << res.size() << endl;
for (size_t i = 0; i < res.size(); ++i) {
cout << i << ": " << (int)static_cast<uint8_t>(res[i]) << endl;
}
exit(1);
return res;
It runs OK, no exceptions, no error. Only the result is wrong. Here is output from running the code:
wstring -> string, input: , size: 11
0: 108
1: 111
2: 114
3: 101
4: 109
5: 32
6: 105
7: 112
8: 115
9: 117
10: 109
lorem ipsum
required size: 11
Result: lorem , size: 11
0: 108
1: 0
2: 111
3: 0
4: 114
5: 0
6: 101
7: 0
8: 109
9: 0
10: 32
I don't understand why are there the null bytes. What am I doing wrong?
Summarizing from comments:
Your code is correct as far as the WideCharToMultiByte logic and arguments go; the only actual problem is the initialization of utf16, which needs to be initialized with a wide literal. The code gives the expected results with both VC++ 2015 RTM and Update 1, so this is a bug in the WideCharToMultiByte emulation layer you're using.
That said, for C++11 onwards, there is a portable solution you should prefer when possible: std::wstring_convert in conjunction with std::codecvt_utf8_utf16
#include <cstddef>
#include <string>
#include <locale>
#include <codecvt>
#include <iostream>
std::string test(std::wstring const& utf16)
{
std::wcout << L"wstring -> string, input: " << utf16 << L", size: " << utf16.size() << L'\n';
for (std::size_t i{}; i != utf16.size(); ++i)
std::wcout << i << L": " << static_cast<int>(utf16[i]) << L'\n';
for (std::size_t i{}; i != utf16.size(); ++i)
std::wcout << utf16[i];
std::wcout << L'\n';
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cvt;
std::string res = cvt.to_bytes(utf16);
std::wcout << L"Result: " << res.c_str() << L", size: " << res.size() << L'\n';
for (std::size_t i{}; i != res.size(); ++i)
std::wcout << i << L": " << static_cast<int>(res[i]) << L'\n';
return res;
}
int main()
{
test(L"lorem ipsum");
}
Online Demo
This is a part of a program that I am writing to compute the addition of two integers as strings. (Writing my own bigInt class).
There appears to be a problem when I am adding the two integers together. Because they are both in vectors of char type, I had to add a '0' to each element of the vector before concatenating it into a string.
However, the results are still not what I am expecting:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
string const Number = "1000";
string const Number2 = "1000";
vector<char> reverse;
vector<char> reverse2;
//cout << (rostrNumber[1] - '0') << endl;
cout << "Original Number: " << Number << endl;
reverse.clear();
for (int i = Number.size() - 1; i >= 0; i--)
{
reverse.push_back(Number[i]);
}
cout << "Reversed: " << endl;
cout << reverse[0] << reverse[1] << reverse[2] << reverse[3] << endl;
cout << endl << endl;
reverse2.clear();
{
for (int i = Number2.size() - 1; i >= 0; i--)
{
reverse2.push_back(Number[i]);
}
}
cout << "Adding these two integers" << endl;
vector<char> const rcvN1 = reverse;
vector<char> const rcvN2 = reverse2;
vector<char> Results;
Results.clear();
//Local copies
vector<char> vN1 = rcvN1;
vector<char> vN2 = rcvN2;
int iSize1 = vN1.size();
int iSize2 = vN2.size();
int i, iSize = iSize2;
int iC = 0, iR;
for (i = 0; i<iSize; i++)
{
iR = vN1[i] + vN2[i] + iC;
if (iR > 9)
{
iR -= 10;
iC = 1;
}
else
iC = 0;
Results.push_back(iR);
cout << Results[0] << endl;
}
if (iC > 0)
Results.push_back(iC);
string ostr;
vector<char>::const_reverse_iterator rIter = Results.rbegin();
for (; rIter != Results.rend(); rIter++)
ostr += *rIter +'0';
cout << "Results: " << ostr << endl;
system("PAUSE");
return 0;
}