Pass InputStream through JNA to C code as a File Pointer
Question
I've got a DLL written in C (that I can't edit) that has some function prototype that looks like
#include <stdio.h>
void foo(FILE *bar);
I'd like to create a JNA interface to the DLL and it's unclear what I need to pass for the FILE *bar argument. I assume I need to pass an InputStream (which is my preference), but the JNA literature seems sparse on the subject.
What would the Java interface look like? and what do I really need to pass to foo?
Edit: foo assumes bar is the result of an fopen and calls operations like fscanf.
Edit 2: Ultimately, I have a string in Java that I need to read in C as if it were a file, (which might be a different question altogether). Ideally I'd like to avoid writing the file, which is why converting an InputStream to a C file pointer is so desirable (and evidently quite difficult).
Solution
I don't believe you can do this - you have no easy way to access the internals of of an InputStream
instance, and even a FileInputStream
will most likely not be implemented on top of a stdio FILE *. To see what your Java interface should be like, you'll need to post more about the foo
function - what it does and how you use it.
If you don't care about what the FILE *
actually does, you can code up using JNA to call fopen
, passing in the file name and open mode, and pass the result as an opaque value through to foo
, e.g. (pseudocode):
path = "MyFile.txt";
bar = Libc.fopen(path, "r");
Libfoo.foo(bar);
Update: If you need to have a string which contains data which you need treated as if it were in a file, I think you are out of luck. Unfortunately, the standard C library is not built on top of a stream abstraction, which means that you are unlikely to be able to achieve what you want unless you can open what looks like a filename but leads to your string data; however, it's going to be much, much easier to bite the bullet and save the string to a temporary file, then open that with fopen
:-(
OTHER TIPS
On POSIX systems, you can do this using a pipe, as long as the string isn't too long (unfortunately "too long" depends on the characteristics of the operating system, but is at least 512 bytes):
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int string_to_foo(const char *str, size_t len)
{
int pipefd[2];
FILE *infile;
if (len > PIPE_BUF)
{
/* Error - string possibly too long */
return -1;
}
if (pipe(pipefd))
{
/* Error - pipe() failed */
return -1;
}
if (write(pipefd[1], str, len) < len)
{
close(pipefd[0]);
close(pipefd[1]);
/* Error - write() failed */
return -1;
}
close(pipefd[1]);
infile = fdopen(pipefd[0], "r");
if (!infile)
{
close(pipefd[0]);
/* Error - fdopen() failed */
return -1;
}
foo(infile);
fclose(infile);
return 0;
}