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.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 12 months ago.
Improve this question
I am following a C++ course which has one challenge in each section. For the most recent challenge, we were to take out three different types of data from a text file, where in one line there are three data types each separated by a tab (only two tabs, you will see).
1\tBox of 64 Pixels\t64 RGB pixels in a decorative box
2\tSense of Humor\tEspecially dry. Imported from England.
3\tBeauty\tInner beauty. No cosmetic surgery required!
4\tBar Code\tUnused. In original packaging.
The first type is the SKU number, the second is the name, and the third is the description. You have to place all this information in a struct.
My solution:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
struct CI
{
int sku = 0;
string name = "";
string desc = "";
};
const int MAXSTRING = 1024;
int main()
{
const char *itemsPath = "items.txt";
FILE *items = fopen(itemsPath, "r");
CI changed1;
CI changed2;
CI changed3;
CI changed4;
vector<CI> changed = {changed1, changed2, changed3, changed4};
vector<string> lines = vector<string>();
char buffer[MAXSTRING];
int tab = 0;
int counter = 0;
while (fgets(buffer, MAXSTRING, items))
{
lines.push_back(buffer);
}
for (string &s : lines)
{
for (char &c : s)
{
if (c == '\t')
{
tab++;
continue;
}
if (tab == 0)
{
changed[counter].sku = c - '0';
}
else if (tab == 1)
{
changed[counter].name += c;
}
else if (tab == 2)
{
changed[counter].desc += c;
}
}
tab = 0;
counter++;
if (counter == 4)
{
break;
}
}
for (int i = 0; i < 4; i++)
{
cout << "sku: " << changed[i].sku << ", name: " << changed[i].name << ", desc: " << changed[i].desc;
}
fclose(items);
return 0;
}
The actual solution:
// 08_solution.cpp by Bill Weinman <http://bw.org/>
// updated 2002-07-23
#include <cstdio>
#include <cerrno>
#include <cstdlib>
#include <cstring>
constexpr size_t maxstring = 1024; // size of line buffer
constexpr size_t name_size = 32; // size of name string
constexpr size_t desc_size = 128; // size of description string
constexpr const char *filename = "/Users/billw/Desktop/ExerciseFiles/Chap08/items.txt";
constexpr size_t max_split = 15;
constexpr char tab_char = '\t';
struct Item
{
int sku; // stock keeping unit
char name[name_size]; // item name
char desc[desc_size]; // item description
};
// str_seps(s) -- returns an array where each element
// represents the position of a separator in the string
// first element is a count
size_t *str_seps(const char *s, size_t len)
{
static size_t indicies[max_split + 1];
size_t &count = indicies[0];
if (len < 3)
return indicies;
for (size_t &z : indicies)
z = 0; // zero out the array
for (size_t i = 0; i < len; ++i)
{
if (s[i] == tab_char)
{
++count;
indicies[count] = i;
if (count >= max_split)
break;
}
}
return indicies;
}
int main()
{
char buf[maxstring]; // buffer for reading lines in file
// open the file
FILE *fr = fopen(filename, "r");
if (!fr)
{
const char *errstr = strerror(errno);
printf("cannot open file (%d): %s\n", errno, errstr);
return 1;
}
// read loop
while (fgets(buf, maxstring, fr))
{
size_t len = strnlen(buf, maxstring);
if (len <= 5)
continue;
// trim the newline from the end of the string
if (buf[len - 1] == '\n')
{
buf[len - 1] = 0;
--len;
}
size_t *split3 = str_seps(buf, len);
if (split3[0] < 2)
break;
buf[split3[1]] = buf[split3[2]] = 0; // change separators to terminators
Item current_item;
current_item.sku = atoi(buf);
strncpy(current_item.name, buf + split3[1] + 1, name_size - 1);
strncpy(current_item.desc, buf + split3[2] + 1, desc_size - 1);
printf("sku: %d, name: %s, desc: %s\n", current_item.sku, current_item.name, current_item.desc);
}
return 0;
}
EDITED: To be specific, is my code unsafe, and is the check to see if the file has been opened or not:
if (!fr)
{
const char *errstr = strerror(errno);
printf("cannot open file (%d): %s\n", errno, errstr);
return 1;
}
needed.
One hint on why it looks odd is at the very beginning:
// updated 2002-07-23
#include <cstdio>
#include <cerrno>
#include <cstdlib>
#include <cstring>
So 20 year old code, using only the C library, might not be great C++.
On the other hand, code like:
CI changed1;
CI changed2;
CI changed3;
CI changed4;
vector<CI> changed = {changed1, changed2, changed3, changed4};
is probably also only obvious to the person writing it. :-)
Guess it means the same as vector<CI> changed(4);, but I had to think about it for a while.
To catch fatal errors like Segmentation Fault during runtime I write a custom SignalHandler that will print a stack trace to console and into a log file.
To achieve this I use (as hundreds before me) the backtrace() and backtrace_symbols() functions in combination with addr2line.
A call to backtrace_symbols() produces following output:
Obtained 8 stack frames.
./Mainboard_Software(+0xb1af5) [0x56184991baf5]
./Mainboard_Software(+0xb1a79) [0x56184991ba79]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x12dd0) [0x7fe72948bdd0]
./Mainboard_Software(causeSIGFPE+0x16) [0x561849918a10]
./Mainboard_Software(_Z13MainboardInit7QString+0xf3) [0x56184990e0df]
./Mainboard_Software(main+0x386) [0x5618499182a3]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xeb) [0x7fe727fd909b]
./Mainboard_Software(_start+0x2a) [0x5618498ff0aa]
I need to pass the offset to addr2line to get my module name and line number.
$ addr2line -C -a -s -f -p -e ./D098_Mainboard_Software 0xb1a79
0x00000000000b1a79: HandleBacktraceSignals at SignalModule.c:492
However, in some modules (especially cpp ones) I get the offset as a combination off sybols and hex, like _Z13MainboardInit7QString+0xf3
I can resolve the symbol to hex with a call to nm:
$ nm Mainboard_Software | grep _Z13MainboardInit7QString
00000000000a3fec T _Z13MainboardInit7QString
Now I can add these two hex numbers, pass them to addr2line and get my module name and line number, even demangled if I want to:
$ addr2line -C -a -s -f -p -e ./D098_Mainboard_Software 0xa40df
0x00000000000a40df: MainboardInit(QString) at MainboardInit.cpp:219
But I want to do the last two steps during runtime. Is there a way to resolve these symbols (e.g. _Z13MainboardInit7QString+0xf3) during runtime so that I can pass them directly to addr2line?
My program consists of both .c and.cpp modules.
You can demangle the symbol run-time by using the library cxxabi:
#include <cxxabi.h>
//...
char *symbolName = "_Z13MainboardInit7QString";
int st;
char* cxx_sname = abi::__cxa_demangle
(
symbolName,
nullptr,
0,
&st
);
The returned cxx_name array contains the demangled symbol.
The address (base and offset) can be recovered from the initial string by a simple parsing using the brackets as start and end delimiters.
Took me a while but with Linux, one can use the dlfcn.h GNU library.
Just be sure to define _GNU_SOURCE above all header file includes.
Beware this include will make your program POSIX nonconform.
For the linker flags add -ldl for both architectures and -g3 for x86 and -g3, -funwind-tables,-mapcs-frame for ARM.
#define _GNU_SOURCE
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dlfcn.h>
#include <gnu/lib-names.h>
#define STACK_FRAMES_BUFFERSIZE (int)128
static void * STACK_FRAMES_BUFFER[128];
static void * OFFSET_FRAMES_BUFFER[128];
static char EXECUTION_FILENAME[32] = "Mainboard_Software";
/*-----------------------------------------------------------------------------------*/
/*
* Function will attempt to backtrace the signal cause by collecting the last called addresses.
* The addresses will then be translated into readable stings by addr2line
*/
static void PrintBacktrace(void)
{
const char errorString[] = "Offset cannot be resolved: No offset present?\n\0?";
char printArray[100] = {0};
size_t bufferEntries;
char ** stackFrameStrings;
size_t frameIterator;
//backtrace the last calls
bufferEntries = backtrace(STACK_FRAMES_BUFFER, STACK_FRAMES_BUFFERSIZE);
stackFrameStrings = backtrace_symbols(STACK_FRAMES_BUFFER, (int)bufferEntries);
//print the number of obtained frames
sprintf(printArray,"\nObtained %zd stack frames.\n\r", bufferEntries);
(void)write(STDERR_FILENO, printArray, strlen(printArray));
//iterate over addresses and print the stings
for (frameIterator = 0; frameIterator < bufferEntries; frameIterator++)
{
#if __x86_64__
//calculate the offset on x86_64 and print the file and line number with addr2line
OFFSET_FRAMES_BUFFER[frameIterator] = CalculateOffset(stackFrameStrings[frameIterator]);
if(OFFSET_FRAMES_BUFFER[frameIterator] == NULL)
{
(void)write(STDERR_FILENO, errorString, strlen(errorString));
}
else
{
Addr2LinePrint(OFFSET_FRAMES_BUFFER[frameIterator]);
}
#endif
#if __arm__
//the address itself can be used on ARM for a call to addr2line
Addr2LinePrint(STACK_FRAMES_BUFFER[frameIterator]);
#endif
}
free (stackFrameStrings);
}
/*-----------------------------------------------------------------------------------*/
/*
* Use add2line on the obtained addresses to get a readable sting
*/
static void Addr2LinePrint(void const * const addr)
{
char addr2lineCmd[512] = {0};
//have addr2line map the address to the relent line in the code
(void)sprintf(addr2lineCmd,"addr2line -C -i -f -p -s -a -e ./%s %p ", EXECUTION_FILENAME, addr);
//This will print a nicely formatted string specifying the function and source line of the address
(void)system(addr2lineCmd);
}
/*-----------------------------------------------------------------------------------*/
/*
* Pass a string which was returned by a call to backtrace_symbols() to get the total offset
* which might be decoded as (symbol + offset). This function will return the calculated offset
* as void pointer, this pointer can be passed to addr2line in a following call.
*/
void * CalculateOffset(char * stackFrameString)
{
void * objectFile;
void * address;
void * offset = NULL;
char symbolString[75] = {'\0'};
char offsetString[25] = {'\0'};
char * dlErrorSting;
int checkSscanf = EOF;
int checkDladdr = 0;
Dl_info symbolInformation;
//parse the string obtained by backtrace_symbols() to get the symbol and offset
parseStrings(stackFrameString, symbolString, offsetString);
//convert the offset from a string to a pointer
checkSscanf = sscanf(offsetString, "%p",&offset);
//check if a symbol string was created,yes, convert symbol string to offset
if(symbolString[0] != '\0')
{
//open the object (if NULL the executable itself)
objectFile = dlopen(NULL, RTLD_LAZY);
//check for error
if(!objectFile)
{
dlErrorSting = dlerror();
(void)write(STDERR_FILENO, dlErrorSting, strlen(dlErrorSting));
}
//convert sting to a address
address = dlsym(objectFile, symbolString);
//check for error
if(address == NULL)
{
dlErrorSting = dlerror();
(void)write(STDERR_FILENO, dlErrorSting, strlen(dlErrorSting));
}
//extract the symbolic information pointed by address
checkDladdr = dladdr(address, &symbolInformation);
if(checkDladdr != 0)
{
//calculate total offset of the symbol
offset = (symbolInformation.dli_saddr - symbolInformation.dli_fbase) + offset;
//close the object
dlclose(objectFile);
}
else
{
dlErrorSting = dlerror();
(void)write(STDERR_FILENO, dlErrorSting, strlen(dlErrorSting));
}
}
return checkSscanf != EOF ? offset : NULL;
}
/*-----------------------------------------------------------------------------------*/
/*
* Parse a string which was returned from backtrace_symbols() to get the symbol name
* and the offset.
*/
void parseStrings(char * stackFrameString, char * symbolString, char * offsetString)
{
char * symbolStart = NULL;
char * offsetStart = NULL;
char * offsetEnd = NULL;
unsigned char stringIterator = 0;
//iterate over the string and search for special characters
for(char * iteratorPointer = stackFrameString; *iteratorPointer; iteratorPointer++)
{
//The '(' char indicates the beginning of the symbol
if(*iteratorPointer == '(')
{
symbolStart = iteratorPointer;
}
//The '+' char indicates the beginning of the offset
else if(*iteratorPointer == '+')
{
offsetStart = iteratorPointer;
}
//The ')' char indicates the end of the offset
else if(*iteratorPointer == ')')
{
offsetEnd = iteratorPointer;
}
}
//Copy the symbol string into an array pointed by symbolString
for(char * symbolPointer = symbolStart+1; symbolPointer != offsetStart; symbolPointer++)
{
symbolString[stringIterator] = *symbolPointer;
++stringIterator;
}
//Reset string iterator for the new array which will be filled
stringIterator = 0;
//Copy the offset string into an array pointed by offsetString
for(char * offsetPointer = offsetStart+1; offsetPointer != offsetEnd; offsetPointer++)
{
offsetString[stringIterator] = *offsetPointer;
++stringIterator;
}
}
Calls to this function will produce output like this on console:
Obtained 11 stack frames.
0x00000000000b1ba5: PrintBacktrace at SignalModule.c:524
0x00000000000b1aeb: HandleBacktraceSignals at SignalModule.c:494
0x0000000000012dd0: ?? ??:0
0x00000000000aea85: baz at testFunctions.c:75
0x00000000000aea6b: bar at testFunctions.c:70
0x00000000000aea5f: foo at testFunctions.c:65
0x00000000000aea53: causeSIGSEGV at testFunctions.c:53
0x00000000000a412f: MainboardInit(QString) at MainboardInit.cpp:218
0x00000000000ae2f3: main at Main.cpp:142 (discriminator 2)
0x000000000002409b: ?? ??:0
0x00000000000950fa: _start at ??:?
Another simple answer:
/*
cc -g -O0 example.c -rdynamic -ldl -o example
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <execinfo.h>
#include <stdlib.h>
extern void print_stack();
extern void* parse_symbol_offset(char* frame);
extern char* addr2line_format(void* addr, char* symbol, char* buffer, int nn_buffer);
char* program = NULL;
int main(int argc, char** argv)
{
program = argv[0];
print_stack();
return 0;
}
void print_stack()
{
void* addresses[64];
int nn_addresses = backtrace(addresses, sizeof(addresses) / sizeof(void*));
printf("%s addresses:\n", program);
for (int i = 0; i < nn_addresses; i++) {
printf("%p\n", addresses[i]);
}
char** symbols = backtrace_symbols(addresses, nn_addresses);
printf("\nsymbols:\n");
for (int i = 0; i < nn_addresses; i++) {
printf("%s\n", symbols[i]);
}
char buffer[128];
printf("\nframes:\n");
for (int i = 0; i < nn_addresses; i++) {
void* frame = parse_symbol_offset(symbols[i]);
char* fmt = addr2line_format(frame, symbols[i], buffer, sizeof(buffer));
int parsed = (fmt == buffer);
printf("%p %d %s\n", frame, parsed, fmt);
}
free(symbols);
}
void* parse_symbol_offset(char* frame)
{
char* p = NULL;
char* p_symbol = NULL;
int nn_symbol = 0;
char* p_offset = NULL;
int nn_offset = 0;
// Read symbol and offset, for example:
// /tools/backtrace(foo+0x1820) [0x555555555820]
for (p = frame; *p; p++) {
if (*p == '(') {
p_symbol = p + 1;
} else if (*p == '+') {
if (p_symbol) nn_symbol = p - p_symbol;
p_offset = p + 1;
} else if (*p == ')') {
if (p_offset) nn_offset = p - p_offset;
}
}
if (!nn_symbol && !nn_offset) {
return NULL;
}
// Convert offset(0x1820) to pointer, such as 0x1820.
char tmp[128];
if (!nn_offset || nn_offset >= sizeof(tmp)) {
return NULL;
}
int r0 = EOF;
void* offset = NULL;
tmp[nn_offset] = 0;
if ((r0 = sscanf(strncpy(tmp, p_offset, nn_offset), "%p", &offset)) == EOF) {
return NULL;
}
// Covert symbol(foo) to offset, such as 0x2fba.
if (!nn_symbol || nn_symbol >= sizeof(tmp)) {
return offset;
}
void* object_file;
if ((object_file = dlopen(NULL, RTLD_LAZY)) == NULL) {
return offset;
}
void* address;
tmp[nn_symbol] = 0;
if ((address = dlsym(object_file, strncpy(tmp, p_symbol, nn_symbol))) == NULL) {
dlclose(object_file);
return offset;
}
Dl_info symbol_info;
if ((r0 = dladdr(address, &symbol_info)) == 0) {
dlclose(object_file);
return offset;
}
dlclose(object_file);
return symbol_info.dli_saddr - symbol_info.dli_fbase + offset;
}
char* addr2line_format(void* addr, char* symbol, char* buffer, int nn_buffer)
{
char cmd[512] = {0};
int r0 = snprintf(cmd, sizeof(cmd), "addr2line -C -p -s -f -a -e %s %p", program, addr);
if (r0 < 0 || r0 >= sizeof(cmd)) return symbol;
FILE* fp = popen(cmd, "r");
if (!fp) return symbol;
char* p = fgets(buffer, nn_buffer, fp);
pclose(fp);
if (p == NULL) return symbol;
if ((r0 = strlen(p)) == 0) return symbol;
// Trait the last newline if exists.
if (p[r0 - 1] == '\n') p[r0 - 1] = '\0';
// Find symbol not match by addr2line, like
// 0x0000000000021c87: ?? ??:0
// 0x0000000000002ffa: _start at ??:?
for (p = buffer; p < buffer + r0 - 1; p++) {
if (p[0] == '?' && p[1] == '?') return symbol;
}
return buffer;
}
Build and run:
cc -g -O0 example.c -rdynamic -ldl -o example
./example
The result is:
./example addresses:
0x559be0516e06
0x559be0516dd1
0x7f6374edec87
0x559be0516cca
symbols:
./example(print_stack+0x2e) [0x559be0516e06]
./example(main+0x27) [0x559be0516dd1]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7f6374edec87]
./example(_start+0x2a) [0x559be0516cca]
frames:
0xe06 1 0x0000000000000e06: print_stack at example.c:26
0xdd1 1 0x0000000000000dd1: main at example.c:20
0x21c87 0 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7f6374edec87]
0xcca 0 ./example(_start+0x2a) [0x559be0516cca]
I am taking a secure computer system course and I am very new to the subject. I am having a problem with an assignment where I need to get a shell by overflowing the buffer in a target program (target.cc). I cannot make any changes in target.cc but I can send the parameters to the target file.
here is the code.
#include <cstdio>
#include <cstring>
#include <cstdlib>
class SubStringReference
{
const char *start;
size_t len;
public:
SubStringReference(const char *s, size_t l) : start(s), len(l) { }
virtual ~SubStringReference() { }
virtual const char *getStart() const { return start; }
virtual int getLen() const { return len; }
};
void print_sub_string(const SubStringReference& str)
{
char buf[252];
if (str.getLen() >= sizeof buf)
{
// Only copy sizeof(buf) - 1 bytes plus a null
memcpy(buf, str.getStart(), sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0'; // null-terminate
}
else
{
printf("by passed mem check\n");
// The length is less than the size of buf so just string copy.
strcpy(buf, str.getStart());
buf[str.getLen()] = '\0'; // null-terminate to get just the substring
}
puts(buf);
}
int main(int argc, char **argv)
{
if (argc != 4)
{
fprintf(stderr, "Usage: %s STRING START LENGTH\n", argv[0]);
return 1;
}
const char *s = argv[1];
int total_len = strlen(s);
int start = atoi(argv[2]);
int len = atoi(argv[3]);
if (start < 0 || start >= total_len)
{
fputs("start is out of range!\n", stderr);
return 1;
}
if (len < 0 || start + len > total_len)
{
fputs("length is out of range!\n", stderr);
return 1;
}
SubStringReference str(s + start, len);
print_sub_string(str);
return 0;
}
Since this program is stackguard protected the program gets aborted before returning. Is there any other way that i can overflow the buffer and get a shell??
Thanks.
Edit - I am running this on a Qemu arm emulator with g++ compiler
The vulnerability can be exploited by overflowing the buffer and overwriting the address of str.getLen() function so as to point to the shell code. Since the canary check is done at the end of the function, shell is got before the canary is checked.
it need a way to call function whose name is stored in a string similar to eval. Can you help?
C++ doesn't have reflection so you must hack it, i. e.:
#include <iostream>
#include <map>
#include <string>
#include <functional>
void foo() { std::cout << "foo()"; }
void boo() { std::cout << "boo()"; }
void too() { std::cout << "too()"; }
void goo() { std::cout << "goo()"; }
int main() {
std::map<std::string, std::function<void()>> functions;
functions["foo"] = foo;
functions["boo"] = boo;
functions["too"] = too;
functions["goo"] = goo;
std::string func;
std::cin >> func;
if (functions.find(func) != functions.end()) {
functions[func]();
}
return 0;
}
There are at least 2 alternatives:
The command pattern.
On windows, you can use GetProcAddress to get a callback by name, and dlopen + dlsym on *nix.
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
double eval( string expression );
int main( int argc, char *argv[] )
{
string expression = "";
for ( int i = 1; i < argc; i++ )
{
expression = expression + argv[i];
}
cout << "Expression [ " << expression << " ] = " << endl;
eval( expression );
}
double eval( string expression )
{
string program = "";
program = program + "#include <cmath>\n";
program = program + "#include <iostream>\n";
program = program + "using namespace std;\n";
program = program + "int main()\n";
program = program + "{\n";
program = program + " cout << ";
program = program + expression;
program = program + " << endl;\n";
program = program + "}";
ofstream out( "abc.cpp" );
out << program;
out.close();
system( "g++ -o abc.exe abc.cpp" );
system( "abc" );
}
You could try to adopt an existing scripting engine, expose the functions you like to this and then use this to evaluate your statements. One such enging could be the V8 engine: https://developers.google.com/v8/intro but there are many alternatives and different languages to choose from.
Here are some examples:
Boost Python
V8
LUA
AngelScript
Except using the function map in the program and hack it on the Makefile, you can access it through ELF.
I think this method is better as it did not need to write duplicate code and compile it every time on different machine.
Here is my demo C/C++ equivalent of eval(“function(arg1, arg2)”)
#include<stdio.h>
#include<stdlib.h>
#include<elf.h>
#include<libelf.h>
#include<unistd.h>
#include<fcntl.h>
#include<gelf.h>
#include<string.h>
void my_fun()
{
int a = 19;
printf("my_fun is excute, a is %d \n", a);
}
void my_fun2()
{
printf("my_fun2 is excute\n");
return;
}
void my_fun3()
{
return;
}
void excute_fun(char *program_name, char *function_name)
{
int i, count;
Elf32_Ehdr *ehdr;
GElf_Shdr shdr;
Elf *elf;
Elf_Scn *scn = NULL;
Elf_Data *data;
int flag = 0;
int fd = open(program_name, O_RDONLY);
if(fd < 0) {
perror("open\n");
exit(1);
}
if(elf_version(EV_CURRENT) == EV_NONE) {
perror("elf_version == EV_NONE");
exit(1);
}
elf = elf_begin(fd, ELF_C_READ, (Elf *) NULL);
if(!elf) {
perror("elf error\n");
exit(1);
}
/* Elf32_Off e_shoff; */
/* if ((ehdr = elf32_getehdr(elf)) != 0) { */
/* e_shoff = ehdr->e_shoff; */
/* } */
/* scn = elf_getscn(elf, 0); */
/* printf("e_shoff is %u\n", e_shoff); */
/* scn += e_shoff; */
while ((scn = elf_nextscn(elf, scn)) != NULL) {
gelf_getshdr(scn, &shdr);
if (shdr.sh_type == SHT_SYMTAB) {
/* found a symbol table. */
break;
}
}
data = elf_getdata(scn, NULL);
if(!shdr.sh_entsize)
count = 0;
else
count = shdr.sh_size / shdr.sh_entsize;
for (i = 0; i < count; ++i) {
GElf_Sym sym;
gelf_getsym(data, i, &sym);
char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name);
if(sym_name != NULL && sym_name[0] != '_' && sym_name[0] != '\0' && sym_name[0] != ' ' && sym.st_value != 0)
{
/* printf("sym_name is %s\n", sym_name); */
/* printf("%s = %X\n", elf_strptr(elf, shdr.sh_link, sym.st_name), sym.st_value); */
if(!strcmp(sym_name, function_name)) {
void (*fun)(void) = (void*)sym.st_value;
(*fun)();
flag = 1;
}
}
}
if(!flag)
printf("can not find this function\n");
elf_end(elf);
close(fd);
}
int main(int argc, char *argv[])
{
char *input = (char*)malloc(100);
for(;;) {
printf("input function_name to excute: ");
scanf("%s", input);
excute_fun(argv[0], input);
memset(input, 0, sizeof(input));
printf("\n");
}
free(input);
return 0;
}
This implementation is based on Example of Printing the ELF Symbol Table
I have a simple program that reads data from a PNG into a 2D array. I would like to save that data to a .RAW file so that Raw Studio or Irfanview can view the raw image that my program outputs to my_out.raw. Currently if I just write the raw binary data to the my_out.raw file, neither application can actually read the file, that is view the image. What do I need to do to the program below so that I can see the image?
The code to read the PNG files is:
// MAIN.cpp
#include "pngfilereader.h"
#include <string>
#include <vector>
#include <fstream>
int main (int argc, char *argv[])
{
PNGFileReader pngfr;
if (!pngfr.decompress_png_to_raw(std::string("/home/matt6809/Downloads"
"/City.png"))) {
std::cout << "File decompression error: " << std::endl;
} else {
std::ofstream out;
out.open("./my_out.raw", std::ios_base::out);
std::vector<std::vector<unsigned char> > data;
pngfr.get_image_data(data);
typedef std::vector<std::vector<unsigned char> >::iterator row_it;
typedef std::vector<unsigned char>::iterator col_it;
for(row_it rit= data.begin(); rit != data.end(); ++rit) {
for(col_it cit = rit->begin(); cit != rit->end(); ++cit) {
out << (*cit);
}
}
out << std::endl;
}
return 0;
}
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <png.h>
#include <iostream>
#include <vector>
#include <string>
class PNGFileReader
{
public:
PNGFileReader();
~PNGFileReader();
// Public exposed API:
bool compress_raw_to_png(uint8_t data, int size);
bool decompress_png_to_raw(const std::string &path);
// Getters
long unsigned int get_image_width();
long unsigned int get_image_height();
void get_image_data(std::vector<std::vector<unsigned char> > &data);
private:
// Helper functions:
bool read_png(const std::string &path);
bool create_png_structs(FILE *fp);
bool free_data();
bool alloc_data();
// Member variables:
png_structp m_pPNG;
png_infop m_pPNGInfo;
png_infop m_pPNGEndInfo;
png_bytepp m_Data;
long unsigned int m_ImageWidth;
long unsigned int m_ImageHeight;
// Enums
enum PNGBOOL {NOT_PNG, PNG};
enum PNGERRORS {ERROR, SUCCESS};
};
#include "pngfilereader.h"
#include <stdexcept>
PNGFileReader::PNGFileReader() :
m_pPNG(NULL),
m_pPNGInfo(NULL),
m_pPNGEndInfo(NULL),
m_Data(NULL),
m_ImageWidth(0),
m_ImageHeight(0)
{
}
PNGFileReader::~PNGFileReader()
{
for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
if (m_Data[i]) {
delete m_Data[i];
m_Data[i] = NULL;
}
}
if (m_Data) {
delete m_Data;
m_Data = NULL;
}
}
// Public Exposed API
bool PNGFileReader::compress_raw_to_png(uint8_t m_Data, int size)
{
return PNGFileReader::SUCCESS;
}
bool PNGFileReader::decompress_png_to_raw(const std::string &path)
{
return read_png(path);
}
// Getters
long unsigned int PNGFileReader::get_image_width()
{
return m_ImageWidth;
}
long unsigned int PNGFileReader::get_image_height()
{
return m_ImageHeight;
}
void PNGFileReader::get_image_data(
std::vector<std::vector<unsigned char> > &data)
{
for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
std::vector<unsigned char> v;
data.push_back(v);
for (unsigned long int j = 0; j < m_ImageWidth; ++j) {
std::vector<unsigned char> *vp = &data[i];
vp->push_back(m_Data[i][j]);
}
}
}
// Private Methods
bool PNGFileReader::read_png(const std::string &path)
{
/*
* Open up the file to read (path) in binary mode
* first so that if anything goes wrong with libpng
* we won't have much to undo
*/
const char *c_path = path.c_str();
FILE *fp = fopen(c_path, "rb");
if (!fp)
return PNGFileReader::ERROR;
/*
* Read the first BYTES_TO_READ bytes from file
* then determine if it is a png file or
* not. If png_sig_cmp == 0 all is okay
*/
enum {BYTES_TO_READ = 8};
unsigned char sig[BYTES_TO_READ];
if (!fread(sig, 1, BYTES_TO_READ, fp)) {
fclose(fp);
return PNGFileReader::ERROR;
}
bool is_png = !png_sig_cmp(sig, 0, BYTES_TO_READ);
if (!is_png) {
fclose(fp);
return PNGFileReader::ERROR;
}
if (!this->create_png_structs(fp)) {
fclose(fp);
return PNGFileReader::ERROR;
}
/*
* For error handling purposes. Set a long pointer
* back to this function to handle all error related
* to file IO
*/
if (setjmp(png_jmpbuf(m_pPNG)))
{
png_destroy_read_struct(&m_pPNG, &m_pPNGInfo, &m_pPNGEndInfo);
fclose(fp);
return PNGFileReader::ERROR;
}
/*
* Set up the input code for FILE openend in binary mode,
* and tell libpng we have already read BYTES_TO_READ btyes from
* signature
*/
png_init_io(m_pPNG, fp);
png_set_sig_bytes(m_pPNG, BYTES_TO_READ);
/*
* Using the lowlevel interface to lib png ...
*/
png_read_info(m_pPNG, m_pPNGInfo);
m_ImageHeight = png_get_image_height(m_pPNG, m_pPNGInfo);
m_ImageWidth = png_get_rowbytes(m_pPNG, m_pPNGInfo);
this->alloc_data();
png_read_image(m_pPNG, m_Data);
png_read_end(m_pPNG, NULL);
png_destroy_read_struct(&m_pPNG, &m_pPNGInfo, &m_pPNGEndInfo);
fclose(fp);
return PNGFileReader::SUCCESS;
}
bool PNGFileReader::create_png_structs(FILE *fp)
{
/*
* Create the pointer to main libpng struct, as well as
* two info structs to maintain information after, and
* prior to all operations on png m_Data. Only necessary
* to release resource after function succeeds.
*/
m_pPNG = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
NULL, NULL);
if (!m_pPNG)
{
fclose(fp);
return PNGFileReader::ERROR;
}
m_pPNGInfo = png_create_info_struct(m_pPNG);
if (!m_pPNGInfo)
{
png_destroy_read_struct(&m_pPNG, (png_infopp)NULL,(png_infopp)NULL);
fclose(fp);
return PNGFileReader::ERROR;
}
m_pPNGEndInfo = png_create_info_struct(m_pPNG);
if (!m_pPNGEndInfo)
{
png_destroy_read_struct(&m_pPNG, &m_pPNGInfo, (png_infopp)NULL);
fclose(fp);
return PNGFileReader::ERROR;
}
return PNGFileReader::SUCCESS;
}
bool PNGFileReader::free_data()
{
if (m_ImageHeight == 0 || m_ImageWidth == 0)
return PNGFileReader::ERROR;
for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
if (m_Data[i]) {
delete m_Data[i];
m_Data[i] = NULL;
}
}
if (m_Data) {
delete m_Data;
m_Data = NULL;
}
return PNGFileReader::SUCCESS;
}
bool PNGFileReader::alloc_data()
{
if (m_ImageHeight == 0 || m_ImageWidth == 0)
return PNGFileReader::ERROR;
if (m_Data != NULL)
this->free_data();
m_Data = new png_bytep[m_ImageHeight]();
for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
m_Data[i] = NULL;
}
try {
for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
m_Data[i] = new png_byte[m_ImageWidth];
}
}
catch (std::bad_alloc e) {
for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
if (m_Data[i]) {
delete m_Data[i];
m_Data[i] = NULL;
}
}
if (m_Data) {
delete m_Data;
m_Data = NULL;
}
throw e;
}
return PNGFileReader::SUCCESS;
}
A "raw" file that is intended to be used with a camera-image processing program like Raw Studio and Irfraview is not a raw-binary dump of the image-data with no header. Instead the "raw" moniker refers to the fact that the image has a minimal amount of image-processing applied in-camera. For instance, the image-data may still be a single-channel monochrome image from the camera's bayer-pattern CFA, or no white-balance, color-matrix, etc. has been applied, etc. Either way, the image-data is still formatted in a standard binary image file format complete with a header, data-packing method, etc. Examples include formats such as Adobe's DNG file format (which is based on TIFF), or proprietary formats from camera manufacturer's themselves such as Canon's CR2, Nikon's NEF, etc.
So if you want these raw-file processing programs to read your "raw" file image data, you'll have to read-up on the binary data specifications the raw-file formats they support, and then re-format the original PNG image-data correctly.