wav file writing and loading using cpp - c++

I have been working on a project based on a wav file with cpp. but no matter what i put in, I always get the output that's only the 1/2 size of the original input. I'm using the algorithm as following:
http://rogerchansdigitalworld.blogspot.com/2010/05/how-to-read-wav-format-file-in-c.html
http://ltheory.com/blog/writeWav.txt
anyone can give a hint?
my main function is:
int main()
{
string filename = "U:\\workspace\\ECE420\\psola.github\\aa.wav";
string directory;
const size_t last_slash_idx = filename.rfind('\\');
if (std::string::npos != last_slash_idx)
{
directory = filename.substr(0, last_slash_idx);
}
string filename1 = "U:\\workspace\\ECE420\\psola.github\\voiceprocessed.wav";
string directory1;
const size_t last_slash_idx1 = filename1.rfind('\\');
if (std::string::npos != last_slash_idx1)
{
directory1 = filename1.substr(0, last_slash_idx1);
}
WavData song;
int num = filename.size();
char file_char[100];
for (int a=0;a<=num;a++){
file_char[a]=filename[a];
}
WavData song1;//
int num1 = filename1.size();
char file_char1[100];
for (int a=0;a<=num1;a++){
file_char1[a]=filename1[a];
}
loadWaveFile(file_char,&song);
cout<<"there are "<<song.size/2<<" samples in this WAV file."<<endl;
writeWAVData(file_char1, song.data, song.size, 44100, 1);
cout<<"2,there are "<<song1.size/2<<" samples in this WAV file."<<endl;
cout<<"success"<<endl;
return 0;
}

Related

libzip zip_fread on image stops at null byte - corrupt images - c++

When trying to unzip an image file using libzip, I have run across the issue where in the image data, I hit a null byte and libzip zip_fread sees this as EOF and stops reading the file, resulting in a corrupted image. What is the best way to get handle the null byte when reading an image and extract the full image?
To clarify, text only files extract perfectly fine.
Below is the code used:
int FileHandler::ExtractFiles(std::string& path, std::string& file, bool is_test)
{
int err = 0;
std::string fullPath = path + "\\" + file;
zip* za = zip_open(fullPath.c_str(), 0, &err);
struct zip_stat st;
zip_stat_init(&st);
int number_of_entries = zip_get_num_entries(za, NULL);
for (zip_uint64_t i = 0; i < number_of_entries; ++i)
{
const char* name = zip_get_name(za, i, NULL);
std::string s_name = name;
size_t pos;
std::string backsl = "\\";
while ((pos = s_name.find(47)) != std::string::npos)
{
s_name.replace(pos, 1, backsl);
}
std::string fullFilePath = path + "\\" + s_name;
if(!is_test)
printf("Extracting: %s...\n", s_name.c_str());
std::string fullDir;
size_t found;
found = fullFilePath.find_last_of("\\");
if (found != std::string::npos)
{
fullDir = fullFilePath.substr(0, found);
}
struct zip_stat ist;
zip_stat_init(&ist);
zip_stat(za, name, 0, &ist);
char* contents = new char[ist.size];
zip_file* f = zip_fopen(za, name, 0);
// zip_fread to contents buffer
zip_fread(f, contents, ist.size);
if (CreateDirectory(fullDir.c_str(), NULL) || ERROR_ALREADY_EXISTS == GetLastError())
{
// writing buffer to file
if (!std::ofstream(fullFilePath).write(contents, ist.size))
{
return EXIT_FAILURE;
}
}
zip_fclose(f);
}
zip_close(za);
return EXIT_SUCCESS;
}
gerum was able to point me in the right direction. For anyone that is wondering or has the same issue, I had to open the ofstream in binary mode and that resolved the issue.
Original code:
// writing buffer to file
if (!std::ofstream(fullFilePath).write(contents, ist.size))
{
return EXIT_FAILURE;
}
Solution:
// writing buffer to file
if (!std::ofstream(fullFilePath, std::ios::binary).write(contents, ist.size))
{
return EXIT_FAILURE;
}

Splitting csv large files into small files with dynamic names using C++

I am a beginner, so I apologise if my question looks childish. I have 38 large files in a folder. I want to split each of the files into smaller parts with dynamic name. Line 1 to line 13 works well. The challenge is in line 16-19. The output shows that the whole data from the ifstream is not appearing as char. This error makes it difficult to split the files. Please what am I getting wrong
#define SEGMENT 728300 //approximate target size of small file
using namespace std;
long file_size(char *name);//function definition below
int main(int argc, char **argv)
{
char input_file_1[100]; // input file
strcpy(input_file_1,argv[1]);
string PathToData = "path to the files";
TString name = PathToData+input_file_1;
std::cout << "Reading file " << name << endl;
char getdata[35000];
ifstream csv_db(name);
while(csv_db.getline(getdata,sizeof(csv_db)))
if (csv_db.eof())
csv_db.close();
int segments=0, i, accum;
FILE *fp1, *fp2;
unsigned int huga=strlen(getdata);
char largeFileName[huga + 100]; // Make sure there's enough space
strcpy(largeFileName, getdata);
std::cout << largeFileName << endl;
std::cout << largeFileName << endl;
long sizeFile = file_size(largeFileName);
segments = sizeFile/SEGMENT + 1980;//ensure end of file
char filename[360]={"path to folder where to keep the result"};
char smallFileName[360];
char line[1080];
fp1 = fopen(largeFileName, "r");
if(fp1)
{
for(i=1980;i<segments;i++)
{
accum = 0;
sprintf(smallFileName, "%s%d.csv", filename, i);
fp2 = fopen(smallFileName, "w");
if(fp2)
{
while(fgets(line, 1080, fp1) && accum <= SEGMENT)
{
accum += strlen(line);//track size of growing file
fputs(line, fp2);
}
fclose(fp2);
}
}
fclose(fp1);
}
return 0;
}
long file_size(char *name)
{
FILE *fp = fopen(name, "rb"); //must be binary read to get bytes
long size=-1;
if(fp)
{
fseek (fp, 0, SEEK_END);
size = ftell(fp)+1;
fclose(fp);
}
return size;
}

Can't load file using fopen()

I creating a program that takes a file and ecrypts it, but now i'am with a problem opening the file to read, the fopen() always return 0.
void run(){
char buffer[260] = { '\0' };
GetWindowTextA(Path,buffer,260);
encryptFile(buffer, "C:\\Users\\DownD\\Desktop\\Some.dat");
}
I think the problem is somewhere on this function run(), because when replace the buffer array with some string for example, "C:\\Somefile.exe" replacing the function encryptFile() for:
encryptFile("C:\\Somefile.exe", "C:\\Users\\DownD\\Desktop\\Some.dat");.It reads the file nice and clean.
Here it is parts of the rest of the project.
int CCrypter::encryptFile(char* filePath, LPCSTR outFile)
{
unsigned char* data = NULL;
int cypherSize;
int fSize = readFile(data, filePath);
if (!fSize)
return 2;
unsigned char *ciphertext = new unsigned char[fSize];
cypherSize = encrypt(data, fSize, ciphertext);
if (!cypherSize)
return 3;
if (!Create_File(ciphertext, cypherSize, outFile))
return 4;
return 1;
}
int CCrypter::readFile(unsigned char *&buffer, const char* path)
{
int lenght = 0;
OutputDebugString(path);
FILE* input = fopen(path, "rb");
if (!input) // Input is always 0
return 0;
fseek(input, 0, SEEK_END);
lenght = ftell(input);
buffer = new unsigned char[lenght];
printf("%d", buffer);
ZeroMemory(buffer, lenght);
rewind(input);
if (!fread(buffer, 1, lenght, input))
return 0;
fclose(input);
return lenght;
}
Just to clarify, i'm using Multi-Byte Character Set
I solved the issue. The problem was that I had opened the file before and did not close it, that was why I was receiving permission denied.

how to make 10 copies of initial file, if first file is as-1.txt second should be as-2.txt and so on

Loop isn't making 10 copies and i have no idea how to change file names
#include "iostream"
#include "fstream"
#include "windows.h"
using namespace std;
void main()
{
char str[200];
ifstream myfile("as-1.txt");
if (!myfile)
{
cerr << "file not opening";
exit(1);
}
for (int i = 0; i < 10; i++)
{
ofstream myfile2("as-2.txt");
while (!myfile.eof())
{
myfile.getline(str, 200);
myfile2 << str << endl;
}
}
system("pause");
}
Solution using plain C API from <cstdio>. Easily customizable.
const char* file_name_format = "as-%d.txt"; //Change that if you need different name pattern
const char* original_file_name = "as-1.txt"; //Original file
const size_t max_file_name = 255;
FILE* original_file = fopen(original_file_name, "r+");
if(!original_file)
//file not found, handle error
fseek(original_file, 0, SEEK_END); //(*)
long file_size = ftell(original_file);
fseek(original_file, 0, SEEK_SET);
char* original_content = (char*)malloc(file_size);
fread(original_content, file_size, 1, original_file);
fclose(original_file);
size_t copies_num = 10;
size_t first_copy_number = 2;
char file_name[max_file_name];
for(size_t n = first_copy_number; n < first_copy_number + copies_num; ++n)
{
snprintf(file_name, max_file_name, file_name_format, n);
FILE* file = fopen(file_name, "w");
fwrite(original_content, file_size, 1, file);
fclose(file);
}
free(original_content);
(*) As noted on this page, SEEK_END may not necessarily be supported (i.e. it is not a portable solution). However most POSIX-compliant systems (including the most popular Linux distros), Windows family and OSX support this without any problems.
Oh, and one more thing. This line
while (!myfile.eof())
is not quite correct. Read this question - it explains why you shouldn't write such code.
int main()
{
const int copies_of_file = 10;
for (int i = 1; i <= copies_of_file; ++i)
{
std::ostringstream name;
name << "filename as-" << i << ".txt";
std::ofstream ofile(name.str().c_str());
ofile.close();
}
return 0;
}
That will make 10 copies of a blank .txt file named "filename as-1.txt" "filename as-2.txt" etc.
Note also the use of int main: main always has a return of int, never void

Is there a better way to search a file for a string?

I need to search a (non-text) file for the byte sequence "9µ}Æ" (or "\x39\xb5\x7d\xc6").
After 5 hours of searching online this is the best I could do. It works but I wanted to know if there is a better way:
char buffer;
int pos=in.tellg();
// search file for string
while(!in.eof()){
in.read(&buffer, 1);
pos=in.tellg();
if(buffer=='9'){
in.read(&buffer, 1);
pos=in.tellg();
if(buffer=='µ'){
in.read(&buffer, 1);
pos=in.tellg();
if(buffer=='}'){
in.read(&buffer, 1);
pos=in.tellg();
if(buffer=='Æ'){
cout << "found";
}
}
}
}
in.seekg((streampos) pos);
Note:
I can't use getline(). It's not a text file so there are probably not many line breaks.
Before I tried using a multi-character buffer and then copying the buffer to a C++ string, and then using string::find(). This didn't work because there are many '\0' characters throughout the file, so the sequence in the buffer would be cut very short when it was copied to the string.
Similar to what bames53 posted; I used a vector as a buffer:
std::ifstream ifs("file.bin");
ifs.seekg(0, std::ios::end);
std::streamsize f_size = ifs.tellg();
ifs.seekg(0, std::ios::beg);
std::vector<unsigned char> buffer(f_size);
ifs.read(buffer.data(), f_size);
std::vector<unsigned char> seq = {0x39, 0xb5, 0x7d, 0xc6};
bool found = std::search(buffer.begin(), buffer.end(), seq.begin(), seq.end()) != buffer.end();
If you don't mind loading the entire file into an in-memory array (or using mmap() to make it look like the file is in memory), you could then search for your character sequence in-memory, which is a bit easier to do:
// Works much like strstr(), except it looks for a binary sub-sequence rather than a string sub-sequence
const char * MemMem(const char * lookIn, int numLookInBytes, const char * lookFor, int numLookForBytes)
{
if (numLookForBytes == 0) return lookIn; // hmm, existential questions here
else if (numLookForBytes == numLookInBytes) return (memcmp(lookIn, lookFor, numLookInBytes) == 0) ? lookIn : NULL;
else if (numLookForBytes < numLookInBytes)
{
const char * startedAt = lookIn;
int matchCount = 0;
for (int i=0; i<numLookInBytes; i++)
{
if (lookIn[i] == lookFor[matchCount])
{
if (matchCount == 0) startedAt = &lookIn[i];
if (++matchCount == numLookForBytes) return startedAt;
}
else matchCount = 0;
}
}
return NULL;
}
.... then you can just call the above function on the in-memory data array:
char * ret = MemMem(theInMemoryArrayContainingFilesBytes, numBytesInFile, myShortSequence, 4);
if (ret != NULL) printf("Found it at offset %i\n", ret-theInMemoryArrayContainingFilesBytes);
else printf("It's not there.\n");
This program loads the entire file into memory and then uses std::search on it.
int main() {
std::string filedata;
{
std::ifstream fin("file.dat");
std::stringstream ss;
ss << fin.rdbuf();
filedata = ss.str();
}
std::string key = "\x39\xb5\x7d\xc6";
auto result = std::search(std::begin(filedata), std::end(filedata),
std::begin(key), std::end(key));
if (std::end(filedata) != result) {
std::cout << "found\n";
// result is an iterator pointing at '\x39'
}
}
const char delims[] = { 0x39, 0xb5, 0x7d, 0xc6 };
char buffer[4];
const size_t delim_size = 4;
const size_t last_index = delim_size - 1;
for ( size_t i = 0; i < last_index; ++i )
{
if ( ! ( is.get( buffer[i] ) ) )
return false; // stream to short
}
while ( is.get(buffer[last_index]) )
{
if ( memcmp( buffer, delims, delim_size ) == 0 )
break; // you are arrived
memmove( buffer, buffer + 1, last_index );
}
You are looking for 4 bytes:
unsigned int delim = 0xc67db539;
unsigned int uibuffer;
char * buffer = reinterpret_cast<char *>(&uibuffer);
for ( size_t i = 0; i < 3; ++i )
{
if ( ! ( is.get( buffer[i] ) ) )
return false; // stream to short
}
while ( is.get(buffer[3]) )
{
if ( uibuffer == delim )
break; // you are arrived
uibuffer >>= 8;
}
Because you said you cannot search the entire file because of null terminator characters in the string, here's an alternative for you, which reads the entire file in and uses recursion to find the first occurrence of a string inside of the whole file.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string readFile (char *fileName) {
ifstream fi (fileName);
if (!fi)
cerr << "ERROR: Cannot open file" << endl;
else {
string str ((istreambuf_iterator<char>(fi)), istreambuf_iterator<char>());
return str;
}
return NULL;
}
bool findFirstOccurrenceOf_r (string haystack, char *needle, int haystack_pos, int needle_pos, int needle_len) {
if (needle_pos == needle_len)
return true;
if (haystack[haystack_pos] == needle[needle_pos])
return findFirstOccurrenceOf_r (haystack, needle, haystack_pos+1, needle_pos+1, needle_len);
return false;
}
int findFirstOccurrenceOf (string haystack, char *needle, int length) {
int pos = -1;
for (int i = 0; i < haystack.length() - length; i++) {
if (findFirstOccurrenceOf_r (haystack, needle, i, 0, length))
return i;
}
return pos;
}
int main () {
char str_to_find[4] = {0x39, 0xB5, 0x7D, 0xC6};
string contents = readFile ("input");
int pos = findFirstOccurrenceOf (contents, str_to_find, 4);
cout << pos << endl;
}
If the file is not too large, your best solution would be to load the whole file into memory, so you don't need to keep reading from the drive. If the file is too large to load in at once, you would want to load in chunks of the file at a time. But if you do load in chucks, make sure you check to edges of the chunks. It's possible that your chunk happens to split right in the middle of the string you're searching for.