I am trying to use a C API in java using JNI. I'm not a C programmer...
Here is the C "object" I have to convert : char *tab[10]
First, I'm not sure what it means : is it a pointer to a tab of char, or a tab of pointers to char ? (and is there any difference ?).
Then, what would the equivalent java object ?
char * tab[10] is pointer to an array of chars (points on first element).
Here is JNI API:
http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/jniTOC.html
Type equivalent for "C char" in JNI is jchar - in java it is "char" primitive type;
Possibilities of What you can do having array of "C chars" are: copy it into existand String object in java OR into java primitive char array.
Usefull link:
http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#array_operations
The 2nd way is may looks like that:
you pass a java char array into JNI call or create new java array from C code with New<PrimitiveType>Array function. However you will end with pointer to array in java.
They copy your C chars into java's one:
jEnv->ReleaseCharArrayElements(javaCharArray, C_CharArray, JNI_COMMIT);
where jEnv - is java enviroment, passing through JNI call. In case u have a pointer u may need to dereference it like *C_CharArray. I think thats may work out.
It's (most likely) an array of 10 strings, and so would be modeled directly as:
String[] tab = new String[10];
It's also possible that it's an array of character buffers, so you might use a StringBuilder instead of a String. And remember, Java arrays are objects in their own right and know their size so that information is not attached to the type (unlike in C, where array sizes are type characteristics).
I'd not expect to have direct transfer of the type/value through JNI; you'll need some conversion glue code in there.
Related
I am using JNA to write a Java interface for a C++ written DLL for control of a small device.
While translating data types I came across
const char*** someVariable
Can someone please explain to me what this means and how can it be recreated in Java?
I have read up on pointers and I am using the JNA documentation to map C++ types to Java but I cannot find a reference to a type with three asterisks at the end.
Should this be interpreted as a pointer to a String array?
if you know the concept of pointers,
const char*** means it is a triple pointer, so you can think of it this way:
const char***--->const char**--->const char*--->const char
So yes it can be interpreted as a pointer to a string array, because a string array can be interpreted as a double pointer.
let's say a is an array of strings:
const char *a[15];
In this case **a would give you the first char of the first string in a.
you can declare:
const char ***b = &a;
in this case ***b would give you the first char of the first string in a.
The most likely interpretation is that you are expected to pass in the address of a pointer, and on return, the pointer will be an array of C strings.
That's not the only possible interpretation, but probably the most likely one. This is especially true if the native signature also asks for a pointer to integer into which it will write the length of the returned array.
To use this from JNA:
PointerByReference pref = new PointerByReference();
IntegerByReference iref = new IntegerByReference();
nativeLib.call(pref, iref);
String[] strings = pref.getValue().getStringArray(0, iref.getValue());
If no length is specified, JNA will look for a NULL value marking the end of the string array.
Assume I have a Frege module
module Util where
total :: [Int] -> Int
total xs = fold (+) 0 xs
If "total" was written in Java, I could call it via
Util.total(Arrays.asList(1,2,3));
What is the best way to call the Frege implementation from Java?
You could use a good old int [] array, the corresponding frege type would be JArray Int. Because arrays can be made from and into lists in both Java and frege, they are good for such tasks.
Please use the repl to get an idea how to convert the array into a list so that you can pass it to your function.
If there are concerns rgd. heap space, there is also a so called ArrayIterator in Data.Iterators, that is an instance of the ListView type class. So another option would be to write your frege so as to take a ListView
total xs = fold (+) 0 xs.toList
and in java call the equivalent of
ArrayIterator.from (... code to create array here ...)
And if you can't change the frege code, or don't want to, you can make a lazy list with
(ArrayIterator.from (... code to create array here ...)).toList
Last but not least, you can fold over the array without converting it before with foldArray.
Is there any built in support for array in XQuery? For example, if we want to implement
the simple java program in xquery how we would do it:
(I am not asking to translate the entire program into xquery, but just asking
how to implement the array in line number 2 of the below code to xquery? I am
using marklogic / xdmp functions also).
java.lang.String test = new String("Hello XQuery");
char[] characters = test.toCharArray();
for(int i = 0; i<characters.length; i++) {
if(character[i] == (char)13) {
character[i] = (char) 0x00;
}
}
Legend:
hex 0x00 dec 0 : null
hex 0x0d dec 13: carriage return
hex 0x0a dec 10: line feed
hex 0x20 dec 22: dquote
The problem with converting your sample code to XQuery is not the absence of support for arrays, but the fact that x00 is not a valid character in XML. If it weren't for this problem, you could express your query with the simple function call:
translate($input, '', '')
Now, you could argue that's cheating, it just happens so that there's a function that does exactly what you are trying to do by hand. But if this function didn't exist, you could program it in XQuery: there are sufficient primitives available for strings to allow you to manipulate them any way you want. If you need to (and it's rarely necessary) you can convert a string to a sequence of integers using the function string-to-codepoints(), and then take advantage of all the XQuery facilities for manipulating sequences.
The lesson is, when you use a declarative language like XQuery or XSLT, don't try to use the same low-level programming techniques you were forced to use in more primitive languages. There's usually a much more direct way of expressing the problem.
XQuery has built-in support for sequences. The function tokenize() (as suggested by #harish.ray) returns a sequence. You can also construct one yourself using braces and commas:
let $mysequence = (1, 2, 3, 4)
Sequences are ordered lists, so you can rely on that. That is slightly different from a node-set returned from an XPath, those usually are document-ordered.
On a side mark: actually, everything in XQuery is either a node-set or a sequence. Even if a function is declared to return one string or int, you can treat that returned value as if it is a sequence of one item. No explicit casting is necessary, for which there are no constructs in XQuery anyhow. Functions like fn:exists() and fn:empty() always work.
HTH!
Just for fun, here's how I would do this in XQuery if fn:translate did not exist. I think Michael Kay's suggestion would end up looking similar.
let $test := "Hello XQuery"
return codepoints-to-string(
for $c in string-to-codepoints($test)
return if ($c eq 32) then 44 else $c)
Note that I changed the transformation because of the problem he pointed: 0 is not a legal codepoint. So instead I translated spaces to commas.
With MarkLogic, another option is to use http://docs.marklogic.com/json:array and its associated functions. The json:set-item-at function would allow coding in a vaguely imperative style. Coding both variations might be a good learning exercise.
There are two ways to do this.
Firstly you can create an XmlResults object using
XmlManager.createResults(), and use XmlResults.add() to add your
strings to this. You can then use the XmlResults object to set the
value of a variable in XmlQueryContext, which can be used in your
query.
Example:
XmlResults values = XMLManager.createResults();
values.add(new XmlValue("value1"));
values.add(new XmlValue("value2"));
XmlQueryContext.setVariableValue("files", values);
The alternative is to split the string in XQuery. You
can do this using the tokenize() function, which works using a
regular expression to match the string separator.
http://www.w3.org/TR/xpath-functions/#func-tokenize
Thanks.
A little outlook: XQuery 3.1 will provide native support for arrays. See http://www.w3.org/TR/xquery-31/ for more details.
You can construct an array like this:
$myArray = tokenize('a b c d e f g', '\s')
// $myArray[3] -> c
Please note that the first index of this pseudo-array is 1 not 0!
Since the question "How to use or implement arrays in XQuery?" is being held generic (and thus shows up in search results on this topic), I would like to add a generic answer for future reference (making it a Community Wiki, so others may expand):
As Christian GrĂ¼n has already hinted at, with XQuery 3.1 XQuery got a native array datatype, which is a subtype of the function datatype.
Since an array is a 'ordered list of values' and an XPath/XQuery sequence is as well, the first question, which may arise, is: "What's the difference?" The answer is simple: a sequence can not contain another sequence. All sequences are automatically flattened. Not so an array, which can be an array of arrays. Just like sequences, arrays in XQuery can also have any mix of any other datatype.
The native XQuery array datatype can be expressed in either of two ways: As [] or via array {}. The difference being, that, when using the former constructor, a comma is being considered a 'hard' comma, meaning that the following array consists of two members:
[ ("apples", "oranges"), "plums" ]
while the following will consist of three members:
array { ("apples", "oranges"), "plums" }
which means, that the array expression within curly braces is resolved to a flat sequence first, and then memberized into an array.
Since Array is a subtype of function, an array can be thought of as an anonymous function, that takes a single parameter, the numeric index. To get the third member of an array, named $foo, we thus can write:
$foo(3)
If an array contains another array as a member you can chain the function calls together, as in:
$foo(3)(5)
Along with the array datatype, special operators have been added, which make it easy to look up the values of an array. One such operator (also used by the new Map datatype) is the question mark followed by an integer (or an expression that evaluates to zero or more integers).
$foo?(3)
would, again, return the third member within the array, while
$foo?(3, 6)
would return the members 3 and 6.
The parenthesis can be left out, when working with literal integers. However, the parens are needed, to form the lookup index from a dynamic expression, like in:
$foo?(3 to 6)
here, the expression in the parens gets evaluated to a sequence of integers and thus the expression would return a sequence of all members from index position 3 to index position 6.
The asterisk * is used as wildcard operator. The expression
$foo?*
will return a sequence of all items in the array. Again, chaining is possible:
$foo?3?5
matches the previos example of $foo(3)(5).
More in-depth information can be found in the official spec: XML Path Language (XPath) 3.1 / 3.11.2 Arrays
Also, a new set of functions, specific to arrays, has been implemented. These functions resinde in the namespace http://www.w3.org/2005/xpath-functions/array, which, conventionally, is being prefixed with array and can be found referenced in here: XPath and XQuery Functions and Operators 3.1 / 17.3 Functions that Operate on Arrays
Given the following declaration in C, I can apply '+' to the address, and access
other elements.
char toto[5];
In other words, applying this operator +
toto+0x04
Accesses a different array element in Java.
Is there another way to implement this operation in java ?
Many Thanks
If I'm right you want to access the element at that position in the array. You can do this in java.
char foo[] = new char[]{'1', '2','3','4', '5'};
char fooAtPositionFour = foo[4];
and assign a new value this way:
foo[4] = 'x';
Technically no since toto+4 is an address and Java's memory management policy is quite different from C's one. However you can get *(toto+4) with toto[4] ;)
Almost always there is another way in java to implement what you want.
You rarely process char[] directly. Using String and StringBuilder is preferred.
String toto = "hello";
String lastChar = toto.substring(4); // from the 4th character.
To answer your question literally. You can use the sun.misc.Unsafe with get/putByte or get/putChar class to do pointer arithmetic, but I suggest avoiding it unless you really, really need to.
in fact i need to isolate the last four byte where param is a char[]
Do you need the last four bytes, or the last char? The last char then toto[toto.length-1]
For the last four bytes you would need to turn the char array (UTF-16 in Java, I've no idea what the encoding would be in C) into a byte array then take the last four bytes.
new String(toto).toBytes("THE_CHAR_ENCODING_YOU_WANT_TO_USE")
I am having some difficulty in understanding how to write the below piece of code using String or char[] in Java.
void xyz(char *a, int startIndex, int endIndex)
{
int j;
for (j = startIndex; j <= endIndex; j++)
{
doThis((a+startIndex), (a+j));
xyz(a, startIndex+1, endIndex);
}
}
Here char *a points to the starting location of the char name[]
The above are just some random functions, but I just want the logic of how to use char* and character index char[] in Java
Based on the rephrased question from the comment thread:
You cannot change the characters of a Java String. If you need to modify a sequence of characters, use StringBuilder, which supports setCharAt(int, char), insert(int, char), and append(char). You can use new StringBuilder(myString) to convert a String to a StringBuilder, and stringBuilder.toString() to convert back.
This is perfectly legit Java code -- it's not code smelly, it's just the way you work with mutable character sequences.
A char* in C is, as you noted, pointing to the start of your character array (which is how C manages Strings).
In C the size of a char is one byte, and pointers always point to the start of a byte. Your C String is an array of characters, so adding 1 to a pointer moves the start of your string right by one character.
That means that the C code:
char *a;
// Set the String here
a = a + 1;
translates in Java to something like:
String a;
// Set the String here
a = a.substring(1);
or if you are using a char array:
char[] a;
// Set the array contents here
char[] copyTo = new char[a.length];
System.arraycopy(a, 1, copyTo, 0, a.length);
a = copyTo;
Java will be a bit more careful of protecting you that C will be though. For instance, if you have a zero length string, the C code has the potential to either segfault (crashing the application) or give you a gibberish string full of memory junk (then, eventually, crash the application), whereas the Java code will throw an exception (normally an IndexOutOfBoundsException) which you can, hopefully, handle cleanly.
Remember though, that String in Java are immutable. You cannot change them, you can only create new Strings. Fortunately, String has several built in functions which allow you to do a lot of the standard actions, like replace part of the String with another and return the result. A character array is mutable, and you can change the characters within them, but you will lose a lot of the nice benefits you get from using the proper String class.
Simple Answer:
You can't do exactly that. Java is pass by reference only. You don't have access to memory location information, so you can't do arithmetic with it.
Longer Answer:
It looks like you are passing in a string for manipulation. You have several options to simulate that.
You can convert the string to an array of characters and then pass in a char[]. If your manipulations are not any sort of standard string operation and completely custom this is probably what you need to do. Keep in mind that you can't change the size of the array passed in, nor can you have a point at a new array after the function completes. (again, only pass by value). Only the values of the existing elements of the array can be modified.
You can pass in the String and use the String methods, such as subString() (which your begin and end indexes seem to suggest, but this may not meet your needs. Note that strings are immutable however, and you can only get a result out via the return statement.
If you really need to modify the contents of the object passed in you can pass a StringBuilder, StringBuffer or CharBuffer object and modify away.
There's a hack that can also be used to circumvent pass by reference, but it's poor style except in special situations. Pass in an array of whatever you need to modify, so in this case an array of array of characters would allow you to set a new sub-array, and effectively acheive pass by reference, but try not to do this :)
If your method modifies the values you cant use String as that is immutable, you can use StringBuilder instead.
If your methods already rely on char arrays and you need the offsets you can use a CharBuffer to wrap an array. It does not support String operations but supports views for sub ranges, which seems to be what you use in the doThis() method.