!!!I have to stick with these functions as I'm not allowed to use any different!!!
A little explanation what I need to do: user input a search directory, then if nothing was found an error message pops up. If something is found, I create an array of one row because at least one file was found and it saves the name of found file. Then if FindNextFIle finds anything I add one row to existing array and this new row saves new found file name.
First output is direct output from the function and the second one is test output of the array to be sure that it worked correctly. Yet it doesn't work saying that memory access is violated so I can't work further.
There's probably 2 reasons why it's not working correctly:
Incorrect add of new row
incorrect print array function
Here's the main():
system("chcp 1251");
drtctrAr drctr;
drctr = createDAr();
WIN32_FIND_DATA FindFileData;
HANDLE hf;
hf = FindFirstFile(drctr.str, &FindFileData);
while (hf == INVALID_HANDLE_VALUE)
{
printf("Error opening files or no files found!\n Try changing the search directory or correct your input!\n");
return 1;
break;
}
StringArray fileNames;
int len;
fileNames.str = (wchar_t**)malloc(sizeof(wchar_t*) * fileNames.rows);
len = wcslen(FindFileData.cFileName)+1;
fileNames.sym = (wchar_t*)malloc(sizeof(wchar_t) * len);
wcscpy_s(fileNames.sym, len, FindFileData.cFileName);
while (FindNextFile(hf, &FindFileData) != 0)
{
printf("Found file: %ls", FindFileData.cFileName);
printf("\n");
fileNames.rows++;
fileNames.str = (wchar_t**)realloc(fileNames.str, sizeof(wchar_t*) * (fileNames.rows));
int len = wcslen(FindFileData.cFileName) + 1;
fileNames.str[fileNames.rows-1] = (wchar_t*)malloc(sizeof(wchar_t) * len);
wcscpy_s(fileNames.str[fileNames.rows-1], len, FindFileData.cFileName);
}
FindClose(hf);
freeDAr(drctr);
printSA(fileNames);
filterSA(fileNames);
freeSA(fileNames);
system("pause");
return 0;
And this is the print function in separate .cpp:
void printSA(StringArray arr)
{
printf("...........................\n");
for (int i = 0; i < arr.rows; i++)
{
for(int j=0;j<arr.sym[i];j++)
printf("Current file: %ls", arr.str[i][j]);
printf("\n");
}
}
And the array struct itself, forgot to add it:
struct StringArray
{
wchar_t** str = NULL;
wchar_t* sym = NULL;
int rows = 1;
};
I mentioned both probable reasons sadly it doesn't mean that these are the correct guess, something at the very start of allocating the array may be wrong
fileNames.str = (wchar_t**)malloc(sizeof(wchar_t*) * fileNames.rows);
len = wcslen(FindFileData.cFileName)+1;
fileNames.sym = (wchar_t*)malloc(sizeof(wchar_t) * len);
wcscpy_s(fileNames.sym, len, FindFileData.cFileName);
This issue exists in above lines. You allocate memory for str but you don't allocate memory for *str / str[0] which is type of wchar_t*. Then you copy file name to fileNames.sym instead of fileNames.str[0], so you don't find the error at first place. Then if second file is found, you allocate memory for fileNames.str[1] and copy the file name to it. This part is correct.
So the access violation excepion happens when you try to access the content of fileNames.str[0] because it is non-allocated memory. If you print fileNames.str[1], it will success.
The following is modified version based on your presented code. It works for me. You can have a try.
#include <stdio.h>
#include <windows.h>
typedef struct StringArray
{
wchar_t** str;
int rows;
}StringArray;
void printSA(StringArray arr)
{
printf("...........................\n");
for (int i = 0; i < arr.rows; i++)
{
printf("Current file: %ls", arr.str[i]);
printf("\n");
}
}
int main()
{
system("chcp 1251");
WIN32_FIND_DATA FindFileData;
HANDLE hf;
hf = FindFirstFile(L"D:\\*.txt", &FindFileData);
while (hf == INVALID_HANDLE_VALUE)
{
printf("Error opening files or no files found!\n Try changing the search directory or correct your input!\n");
return 1;
break;
}
StringArray fileNames;
fileNames.rows = 1;
int len;
fileNames.str = (wchar_t**)malloc(sizeof(wchar_t*) * fileNames.rows);
len = wcslen(FindFileData.cFileName) + 1;
fileNames.str[fileNames.rows - 1] = (wchar_t*)malloc(sizeof(wchar_t) * len);
wcscpy_s(fileNames.str[fileNames.rows - 1], len, FindFileData.cFileName);
while (FindNextFile(hf, &FindFileData) != 0)
{
printf("Found file: %ls", FindFileData.cFileName);
printf("\n");
fileNames.rows++;
fileNames.str = (wchar_t**)realloc(fileNames.str, sizeof(wchar_t*) * (fileNames.rows));
int len = wcslen(FindFileData.cFileName) + 1;
fileNames.str[fileNames.rows - 1] = (wchar_t*)malloc(sizeof(wchar_t) * len);
wcscpy_s(fileNames.str[fileNames.rows - 1], len, FindFileData.cFileName);
}
FindClose(hf);
printSA(fileNames);
// TODO: Free pointers
// ...
system("pause");
return 0;
}
Related
Basically, what I am trying to do is to find last section of PE file. I have read PE specification very attentively, yet I can't discover where my code fails.
PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)(pidh + pidh->e_lfanew);
PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
PIMAGE_OPTIONAL_HEADER pioh = (PIMAGE_OPTIONAL_HEADER)&pinh->OptionalHeader;
PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)(pinh + sizeof(IMAGE_NT_HEADERS) + (pifh->NumberOfSections - 1) * sizeof(IMAGE_SECTION_HEADER));
buffer is a byte array containing loaded executable, and pish is a pointer to the last section. For some reason, it appears that number of sections is over 20 000.
Any ideas ?
Thanks in advance
There is one problem I see off hand: e_lfanew is the offset to the IMAGE_NT_HEADERS structure in bytes. You are adding this number of bytes to a IMAGE_DOS_HEADER pointer, so you are moving forward by sizeof(IMAGE_DOS_HEADER)*pidh->e_lfanew bytes.
Fixed version:
PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE*)pidh + pidh->e_lfanew);
PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
PIMAGE_OPTIONAL_HEADER pioh = (PIMAGE_OPTIONAL_HEADER)&pinh->OptionalHeader;
PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)((BYTE*)pinh + sizeof(IMAGE_NT_HEADERS) + (pifh->NumberOfSections - 1) * sizeof(IMAGE_SECTION_HEADER));
The best way to debug problems like this is to drop into the code with your debugger and view the PE data yourself in memory. You can open up the Visual Studio hex editor for example and see all of the byte data, and which values you are actually reading out.
Here's some information on viewing program memory in VS 2010:
http://msdn.microsoft.com/en-us/library/s3aw423e.aspx
Various section address and data can be obtained by below way also :
#include<windows.h>
#include<iostream>
int main()
{
LPCSTR fileName="inputFile.exe";
HANDLE hFile;
HANDLE hFileMapping;
LPVOID lpFileBase;
PIMAGE_DOS_HEADER dosHeader;
PIMAGE_NT_HEADERS peHeader;
PIMAGE_SECTION_HEADER sectionHeader;
hFile = CreateFileA(fileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if(hFile==INVALID_HANDLE_VALUE)
{
std::cout<<"\n CreateFile failed \n";
return 1;
}
hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);
if(hFileMapping==0)
{
std::cout<<"\n CreateFileMapping failed \n";
CloseHandle(hFile);
return 1;
}
lpFileBase = MapViewOfFile(hFileMapping,FILE_MAP_READ,0,0,0);
if(lpFileBase==0)
{
std::cout<<"\n MapViewOfFile failed \n";
CloseHandle(hFileMapping);
CloseHandle(hFile);
return 1;
}
dosHeader = (PIMAGE_DOS_HEADER) lpFileBase;
if(dosHeader->e_magic==IMAGE_DOS_SIGNATURE)
{
std::cout<<"\n DOS Signature (MZ) Matched \n";
peHeader = (PIMAGE_NT_HEADERS) ((u_char*)dosHeader+dosHeader->e_lfanew);
if(peHeader->Signature==IMAGE_NT_SIGNATURE)
{
std::cout<<"\n PE Signature (PE) Matched \n";
sectionHeader = IMAGE_FIRST_SECTION(peHeader);
UINT nSectionCount = peHeader->FileHeader.NumberOfSections;
//No of Sections
std::cout<<"\n No of Sections : "<<nSectionCount<<" \n";
//sectionHeader contains pointer to first section
//sectionHeader++ will move to next section
for( UINT i=0; i<nSectionCount; ++i, ++sectionHeader )
{
std::cout<<"\n-----------------------------------------------\n";
std::cout<<"\n Section Name : "<<sectionHeader->Name<<" \n";
//address can be obtained as (PBYTE)lpFileBase+sectionHeader->PointerToRawData
std::cout<<"\n Size of section data : "<<sectionHeader->Misc.VirtualSize<<" \n";
std::cout<<"\n-----------------------------------------------\n";
}
//Now sectionHeader will have pointer to last section
//if you add sectionHeader++ in for loop instead of ++sectionHeader it will point to memory after last section
}
else
{
return 1;
}
}
else
{
return 1;
}
return 0;
}
You just do it the wrong way.
I wrote some code for you, hope it helps.It can show the data of the last section of a PE file.
#include <stdio.h>
#include <malloc.h>
#include <windows.h>
void ShowHexData(BYTE *ptr,DWORD len)
{
int index = 0;
int i = 0;
const int width = 16;
while(index + width < len)
{
int i;
for(i = 0; i < width; ++i)
{
printf(" %02X",ptr[index + i]);
}
printf(" \t");
for(i = 0; i < width; ++i)
{
if(ptr[index + i] >= 0x20 &&
ptr[index + i] <= 0x7F)
{
putchar(ptr[index + i]);
}else{
putchar('.');
}
}
index += width;
putchar('\n');
}
for(i = 0; index + i < len; ++ i)
{
printf(" %02X",ptr[index + i]);
}
while(i < width)
{
printf(" ");
i += 1;
}
printf(" \t");
for(i = 0; index + i < len; ++ i)
{
if(ptr[index + i] >= 0x20 &&
ptr[index + i] <= 0x7F)
{
putchar(ptr[index + i]);
}else{
putchar('.');
}
}
putchar('\n');
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("Usage : %s filename\n",argv[0]);
return -1;
}else{
FILE *fp = fopen(argv[1],"rb");
IMAGE_DOS_HEADER DosHeader = {0};
IMAGE_FILE_HEADER FileHeader = {0};
IMAGE_SECTION_HEADER SectionHeader = {0};
DWORD Signature = 0;
DWORD RawPointerToPeHeader = 0, SizeOfFile = 0;
DWORD SectionCount = 0;
DWORD ByteCount = 0;
BYTE *pData = NULL;
if(!fp)
{
perror("");
return -1;
}
fseek(fp,0,SEEK_END);
SizeOfFile = ftell(fp);
if(SizeOfFile <
sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS))
goto not_pe_file;
fseek(fp,0,SEEK_SET);
fread(&DosHeader,1,sizeof DosHeader,fp);
if(DosHeader.e_magic != 'M' + 'Z' * 256)
goto not_pe_file;
RawPointerToPeHeader = DosHeader.e_lfanew;
if(SizeOfFile <=
RawPointerToPeHeader + sizeof(IMAGE_NT_HEADERS))
goto not_pe_file;
fseek(fp,RawPointerToPeHeader,SEEK_SET);
fread(&Signature,1,sizeof(DWORD),fp);
if(Signature != 'P' + 'E' * 256)
goto not_pe_file;
fread(&FileHeader,1,sizeof FileHeader,fp);
if(FileHeader.SizeOfOptionalHeader !=
sizeof(IMAGE_OPTIONAL_HEADER))
goto not_pe_file;
SectionCount = FileHeader.NumberOfSections;
if(SectionCount == 0)
{
printf("No section for this file.\n");
fclose(fp);
return -1;
}
if(SizeOfFile <=
RawPointerToPeHeader +
sizeof(IMAGE_NT_HEADERS) +
SectionCount * sizeof(IMAGE_SECTION_HEADER))
goto not_pe_file;
fseek(fp,
RawPointerToPeHeader + sizeof(IMAGE_NT_HEADERS) +
(SectionCount - 1) * sizeof(IMAGE_SECTION_HEADER),
SEEK_SET);
fread(&SectionHeader,1,sizeof SectionHeader,fp);
ByteCount = SectionHeader.Misc.VirtualSize < SectionHeader.PointerToRawData ?
SectionHeader.Misc.VirtualSize : SectionHeader.PointerToRawData;
if(ByteCount == 0)
{
printf("No data to read for target section.\n");
fclose(fp);
return -1;
}else if(ByteCount + SectionHeader.PointerToRawData > SizeOfFile)
{
printf("Bad section data.\n");
fclose(fp);
return -1;
}
fseek(fp,SectionHeader.PointerToRawData,SEEK_SET);
pData = (BYTE*)malloc(ByteCount);
fread(pData,1,ByteCount,fp);
ShowHexData(pData,ByteCount);
free(pData);
fclose(fp);
return 0;
not_pe_file:
printf("Not a PE file.\n");
fclose(fp);
return -1;
}
return 0;
}
In short, you do not know where the data is, until you analyze the data according to the file header.
sections pointer:
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh); // definition
in winnt.h
or
PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER )((BYTE*)pioh +
pifh->SizeOfOptionalHeader);
the last section pointer is:
PIMAGE_SECTION_HEADER pilsh = &pish[pifh->NumberOfSections-1]
My programme keeps producing a segmentation fault.
I have simplified my code to the following:
#include <stdio.h>
void open_file(FILE** file)
{
*file = fopen("test" , "wb");
return;
}
int main ()
{
int Tracks = 1;
FILE* Files;
int i = 1;
Files = new FILE[Tracks + 1];
printf("i = %d\n", i); //i = 1
open_file(&Files + i);
printf("i = %d\n", i); /i = 0
fclose(*(&Files + i)); //Segmentation fault
return 0;
}
I must be doing some really stupid pointer-error, but to me my pointer-arithmetics operations look fine... The problem is, that for some magic reason, the variable i changes its value to 0. Could someone explain to me why??
Thanks in advance!
The problem is one of operator precedence, where the address-of operator have higher precedence than the addition operator. That means you are doing e.g. (&Files) + i, which is equivalent to (&Files)[i].
fopen return a FILE*, so you may want to use an array of FILE* or a FILE** to store many of it.
Also you have to check the file to be opened before closing it.
#include <stdio.h>
void open_file(FILE** file)
{
*file = fopen("test" , "wb");
return;
}
int main ()
{
int Tracks = 1;
FILE** Files = new FILE*[Tracks + 1];
int i = 1;
printf("i = %d\n", i); //i = 1
open_file(&Files[i]); // Will write at the address of the i-th element of Files.
printf("i = %d\n", i); //i = 1
// This have to be done for each element that correspond to an open file.
// Add a for-loop should be considered.
if (Files[i]) // Avoid segmentation fault
{
fclose(Files[i]);
Files[i] = 0; // So I know it is closed.
}
delete[] Files;
return 0;
}
About the Files[i] = 0; you can take a look here.
About the magic i modification.
Here what happens :
void open_file(FILE** file)
{
// Write file address or 0 at the given address.
*file = fopen("test" , "wb");
return;
}
int main ()
{
int Tracks = 1;
FILE* Files = new FILE[Tracks + 1]; // Files at address a
int i = 1; // i probably at address a + sizeof(FILE*)
printf("i = %d\n", i); // i = 1
// here i = 1 so &Files + i = &Files + 1 = address of i.
open_file(&Files + i); // Call to open_file with the address of i !
// open_file failed and write 0 to the given address.
printf("i = %d\n", i); // i = 0
}
Am working in a project where i have to read a set of files and put it in a buffer.The List comprises of small as well as large files.I have to read these files and for more efficiency i tried implementing it in multiple threads.Each thread will take a file from vector of file names and start reading it put it into a buffer and these buffer have to be put in a queue.I happened to have some error in program and i i don't know where exactly in my program the error occurs also don't know why ? Please help me whether there is any mistake in my logic or in my code and how to correct it. Thanks in advance
using namespace std;
#define MAX_THREADS 2
#define BUFFER_SIZE 8388608
vector<string>files;
deque<string>bufferq;
CRITICAL_SECTION Readlock;
int count = 0;
DWORD WINAPI ReadThread(LPVOID s);
int main(int argc,char *argv[])
{
HANDLE ReadT[MAX_THREADS];
char *filelist[5];
DWORD threadid;
filelist[0] = "1.txt";
filelist[1] = "cloudy.jpg";
filelist[2] = "connectify.exe";
filelist[3] = "VMware.exe";
filelist[4] = "Sherlock.mp4";
for(int i=0;i<5;i++)
files.push_back(filelist[i]);
InitializeCriticalSection(&Readlock);
long t1 = GetTickCount();
for(int k = 0; k< MAX_THREADS; k++)
ReadT[k] = CreateThread(NULL,0,ReadThread,NULL,NULL,&threadid);
WaitForMultipleObjects(MAX_THREADS,ReadT,TRUE,INFINITE);
cout << " Time Taken "<< GetTickCount()-t1 << "ms" ;
system("pause");
return 0;
}
DWORD WINAPI ReadThread(LPVOID s)
{
long pending = 0;
//int freespace = BUFFER_SIZE;
char *filename = new char[50];
char fsize[10];
string file;
char *buf;
buf = new char[BUFFER_SIZE];
long filesize = 0;
int numfiles = files.size();
int filled = 0;
int i = 0;
FILE *fp;
char* ptr;
ptr = buf;
while(true)
{
EnterCriticalSection(&Readlock);
if(files.empty())
{
LeaveCriticalSection(&Readlock);
break;
}
else
{
file = files.front();
files.erase(files.begin());
LeaveCriticalSection(&Readlock);
}
bool buff_full = false;
buf = ptr;
int freespace = BUFFER_SIZE;
memset(buf,0,BUFFER_SIZE);
if(!buff_full)
{
if(pending == 0)
{
fp = fopen(file.c_str(),"rb");
if(!fp)
{
cout<<"\nNo such file";
cout<<files[i];
system("pause");
return 0;
}
int r1 =fseek(fp, 0L, SEEK_END);
filesize = ftell(fp);
int r2 =fseek(fp, 0L, SEEK_SET);
sprintf(fsize, "%ld", filesize);
if(freespace >= (strlen(fsize) + strlen(file.c_str()) + 2))
{
count++;
memcpy(buf, file.c_str(), strlen(file.c_str())+1);
freespace = freespace - strlen(file.c_str()) - 1;
buf += strlen(file.c_str()) + 1;
memcpy(buf,fsize,strlen(fsize)+1);
buf += strlen(fsize) + 1;
freespace = freespace - strlen(fsize) - 1;
cout<<"Files read is "<<count<<"\n";
if(freespace == 0)
{
buff_full = true;
pending = filesize;
break;
}
}
else
{
filled = BUFFER_SIZE - freespace;
fclose(fp);
break;
}
if(freespace >= filesize)
{
fread(buf, 1, filesize, fp);
buf += filesize;
freespace = freespace - filesize;
bufferq.push_back(buf);
//cout << "pop"<<bufferq.size();
//i++;
if(files.empty())
{
filled = BUFFER_SIZE - freespace;
fclose(fp);
break;
}
fclose(fp);
}
else
{
fread(buf, 1, freespace, fp);
bufferq.push_back(buf);
//cout <<"pop "<<bufferq.size();
buff_full = true;
}
}
else
{
if(freespace >= pending)
{
fread(buf, 1, pending, fp);
bufferq.push_back(buf);
freespace = freespace - pending;
pending = 0;
//i++;
if(files.empty())
{
filled = BUFFER_SIZE - freespace;
fclose(fp);
break;
}
if(freespace > 0)
buf += pending;
else
buff_full = true;
fclose(fp);
}
else
{
fread(buf, 1, freespace, fp);
bufferq.push_back(buf);
cout << bufferq.size();
pending = pending - freespace;
buff_full = true;
}
}
}
if(buff_full)
{
buf = ptr;
cout << "popping buffer " << bufferq.size();
//bufferq.pop_back();
}
}
return 0;
}
In the context that bug occurs on big files, I suppose that this line can cause problems
sprintf(fsize, "%ld", filesize);
fsize is char[10], and if filesize is >= 1,000,000,000 you'll overwrite fsize array with trailing 0. This will cause "Run-Time Check Failure #2 - Stack around the variable 'fsize' was corrupted.", as you wrote. Please check the sizes of your test files.
Among others, you are filling files in loop on i, and then you wrote:
files.erase(files.begin());
// ...
cout<<"\nNo such file";
cout<<files[i];
files[i] already points to another element as you erased them, and if files are empty on the last iteration it will cause crash.
And what for are you copying file and fsize to buf if you do not copy it to the bufferq?
As bufferq is writable and is shared between threads the access to it should be protected by lock, critical section as you chose.
That's my little code review.
I want to search a file which may be present in any drives such as C:\, D:\ etc. Using GetLogicalDriveStrings I can able to get the list of drives but when I add anything extra for the output, I am getting a null in the output prompt. Here is my code:
#include "StdAfx.h"
#include <windows.h>
#include <stdio.h>
#include <conio.h>
// Buffer length
DWORD mydrives = 100;
// Buffer for drive string storage
char lpBuffer[100];
const char *extFile = "text.ext";
// You may want to try the wmain() version
int main(void)
{
DWORD test;
int i;
test = GetLogicalDriveStrings(mydrives, (LPWSTR)lpBuffer);
if(test != 0)
{
printf("GetLogicalDriveStrings() return value: %d, Error (if any): %d \n", test, GetLastError());
printf("The logical drives of this machine are:\n");
// Check up to 100 drives...
for(i = 0; i<100; i++)
printf("%c%s", lpBuffer[i],extFile);
printf("\n");
}
else
printf("GetLogicalDriveStrings() is failed lor!!! Error code: %d\n", GetLastError());
_getch();
return 0;
}
I want above output as C:\text.ext D:\text.ext ... rather I am getting text.ext only. I am using Microsoft Visual C++ 2010 Express
GetLogicalDriveStrings() returns a double-null terminated list of null-terminated strings. E.g., say you had drives A, B and C in your machine. The returned string would look like this:
A:\<nul>B:\<nul>C:\<nul><nul>
You can use the following code to iterate through the strings in the returned buffer and print each one in turn:
DWORD dwSize = MAX_PATH;
char szLogicalDrives[MAX_PATH] = {0};
DWORD dwResult = GetLogicalDriveStrings(dwSize,szLogicalDrives);
if (dwResult > 0 && dwResult <= MAX_PATH)
{
char* szSingleDrive = szLogicalDrives;
while(*szSingleDrive)
{
printf("Drive: %s\n", szSingleDrive);
// get the next drive
szSingleDrive += strlen(szSingleDrive) + 1;
}
}
Note that the details of how the function works, including the example code that I shamelessly copied and pasted, can be found by reading the docs.
Did you mean to put the printf in the loop?
Currently, you set extFile 100 times (just to be sure?!)
for(i = 0; i<100; i++)
extFile = "text.ext";
You meant to show all the drive letters in a loop:
for(i = 0; i<100; i++)
{
extFile = "text.ext";
printf("%c%s", lpBuffer[i], extFile); //I guess you mean extFile here?
}
DWORD dwSize = MAX_PATH;
WCHAR szLogicalDrives[MAX_PATH] = { 0 };
DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
CStringArray m_Drives;
m_Drives.RemoveAll();
if (dwResult > 0 && dwResult <= MAX_PATH)
{
WCHAR* szSingleDrive = szLogicalDrives;
while (*szSingleDrive)
{
UINT nDriveType = GetDriveType(szSingleDrive);
m_Drives.Add(CString(szSingleDrive, 2));
// get the next drive
szSingleDrive += wcslen(szSingleDrive) + 1;
}
}
return m_Drives;
class DriveList {
protected:
LPTSTR m_driveList;
DWORD m_driveCount;
DWORD m_bufSize = 32 * sizeof(TCHAR);
public:
virtual ~DriveList() {
free(m_driveList);
}
DriveList() {
m_driveList = (LPTSTR)malloc(m_bufSize);
}
int getDriveCount() const {
return m_driveCount;
}
TCHAR operator[] (const int index) const {
return m_driveList[index];
}
void loadDriveList() {
DWORD mask;
if((mask = GetLogicalDrives()) == 0) {
throw;
}
m_driveCount = 0;
for(int x = 0; x <= 25; x++ ) {
if(mask & 1) {
m_driveList[m_driveCount] = TCHAR(65 + x);
m_driveCount += 1;
}
mask >>= 1;
}
}
};
I want to get the suffix(.txt,.png etc.) of a file that I know that exists in some folder.
I know that the file name(prefix) is unique in this folder.
The language is c++.
thanks
Assuming that "suffix" is the filename extension, you can do this:
char * getfilextension(char * fullfilename)
{
int size, index;
size = index = 0;
while(fullfilename[size] != '\0') {
if(fullfilename[size] == '.') {
index = size;
}
size ++;
}
if(size && index) {
return fullfilename + index;
}
return NULL;
}
It's C code, but I believe that can easily ported to C++(maybe no changes).
getfilextension("foo.png"); /* output -> .png */
I hope this help you.
UPDATE:
You will need scan all files of directory and compare each file without extension if is equal to your target.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#include <dirent.h>
#include <string.h>
//.....
char * substr(char * string, int start, int end)
{
char * p = &string[start];
char * buf = malloc(strlen(p) + 1);
char * ptr = buf;
if(!buf) return NULL;
while(*p != '\0' && start < end) {
*ptr ++ = *p++;
start ++;
}
*ptr++ = '\0';
return buf;
}
char * getfilenamewithoutextension(char * fullfilename)
{
int i, size;
i = size = 0;
while(fullfilename[i] != '\0') {
if(fullfilename[i] == '.') {
size = i;
}
i ++;
}
return substr(fullfilename, 0, size);
}
char * getfilextension(char * fullfilename)
{
int size, index;
size = index = 0;
while(size ++, fullfilename[size]) {
if(fullfilename[size] == '.') {
index = size;
}
}
if(size && index) {
return fullfilename + index;
}
return NULL;
}
char*FILE_NAME;
int filefilter(const struct dirent * d)
{
return strcmp(getfilenamewithoutextension((char*)d->d_name), FILE_NAME) == 0;
}
and then:
void foo(char * path, char * target) {
FILE_NAME = target;
struct dirent ** namelist;
size_t dirscount;
dirscount = scandir(path, &namelist, filefilter, alphasort);
if(dirscount > 0) {
int c;
for(c = 0; c < dirscount; c++) {
printf("Found %s filename,the extension is %s.\n", target, getfilextension(namelist[c]->d_name));
free(namelist[c]);
}
free(namelist);
} else {
printf("No files found on %s\n", path);
}
}
and main code:
int main(int argc, char * argv[])
{
foo(".", "a"); /* The .(dot) scan the current path */
}
For a directory with this files:
a.c a.c~ a.out
a.o makefile test.cs
The output is:
Found a filename,the extension is .c.
Found a filename,the extension is .c~.
Found a filename,the extension is .o.
Found a filename,the extension is .out.
Note: the scandir() function is part of GNU extensions/GNU library,if you don't have this function available on your compiler,tell me that I will write an alias for that or use this implementation(don't forget to read the license).
If you're using Windows, use PathFindExtension.
There's no standard functionality to list directory contents in c++. So if you know allowed extensions in your app you can iterate through and find if file exists.
Other options are use OS specific API or use something like Boost. You can also use "ls | grep *filename" or "dir" command dump and parse the output.