How to represent a C char array in Java with GraalVm - graalvm

I'm consuming a C library in Java with GraalVm and I have this field (if_name) I don't know how to implement:
# define IFNAMSIZ 16
struct port_t
{
char if_name[IFNAMSIZ];
}
This is my current code:
#CStruct("port_t")
interface Port extends PointerBase {
#CField("if_name")
WordPointer getIfName();
#CField("if_name")
void setIfName(WordPointer ifName);
}
Using WordPointer I get the following error compiling:
Error: Type WordPointer has a size of 8 bytes, but accessed C value has a size of 16 bytes; to suppress this error, use the annotation #AllowNarrowingCast
I already tried with CCharPointer and CCharPointerPointer but those have fixed lengths to 8 bytes and I got a similar error when compiling.
Anyone can help?
Thanks in advance

As you already guessed, you'll need to get the address of this field to manipulate it.
You can use
#CStruct("port_t")
interface Port extends PointerBase {
#CFieldAddress("if_name")
CCharPointer addressOfIfName();
}
In this case it doesn't make sense to have a setter since you cannot change the address of this field. Instead you can use the read/write methods of CCharPointer.
You'll probably need
#CConstant
static native int IFNAMSIZ();
somewhere as well.
Then you can do things like
String foo(Port p, String newIfName) {
UnsignedWord size = WordFactory.unsigned(IFNAMSIZ());
String oldIfName = CTypeConversion.toJavaString(p.addressOfIfName(), size);
CTypeConversion.toCString(newIfName, p.addressOfIfName(), size);
return oldIfName;
}

Related

Null Assertions in null-safe mode and How to Avoid If Possible

Learning Dart and using dart_code_metrics to ensure that I write code that meets expectations. One of the rules that is active is avoid-non-null-assertion.
Note, the code below was created to recreate the problem encountered in a larger code base where the value of unitString is taken from a JSON file. As such the program cannot control what is specified in the JSON file.
From pubspec.yaml
environment:
sdk: '>=2.15.0 <3.0.0'
// ignore_for_file: avoid_print
import 'package:qty/qty.dart';
void main() {
const String unitString = 'in';
// unit.Width returns null if unitString is not a unit of Length.
if (Length().unitWith(symbol: unitString) == null) {
print('units $unitString not supported.');
} else {
// The following line triggers avoid-non-null-assertion with the use of !.
final Unit<Length> units = Length().unitWith(symbol: unitString)!;
final qty = Quantity(amount: 0.0, unit: units);
print('Qty = $qty');
}
}
If I don't use ! then I get the following type error:
A value of type 'Unit<Length>?' can't be assigned to a variable of type 'Unit<Length>'.
Try changing the type of the variable, or casting the right-hand type to 'Unit<Length>'.
Casting the right-hand side to
Unit<Length>
fixes the above error but cause a new error when instantiating Quantity() since the constructor expects
Unit<Length>
and not
Unit<Length>?
I assume there is an solution but I'm new to Dart and cannot formulate the correct search query to find the answer.
How can I modify the sample code to make Dart and dart_code_metrics happy?
Your idea of checking for null before using a value is good, it's just not implemented correctly. Dart does automatically promote nullable types to non-null ones when you check for null with an if, but in this case you need to use a temporary variable.
void main() {
const String unitString = 'in';
//Use a temp variable, you could specify the type instead of using just using final
final temp = Length().unitWith(symbol: unitString);
if (temp == null) {
print('units $unitString not supported.');
} else {
final Unit<Length> units = temp;
final qty = Quantity(amount: 0.0, unit: units);
print('Qty = $qty');
}
}
The basic reason for that when you call your unitWith function and see that it's not null the first time, there's no guarantee that the when you call it again that it will still return a non-null value. I think there's another SO question that details this better, but I can't seem to find.

Get pointer to a struct from a Dart_NativeArguments struct in C

I'm trying to wrap a C library using Dart. I call into a C function from dart and pass in the arguments through a Dart_NativeArguments struct in C:
void _sayHello(Dart_NativeArguments arguments) {
string from;
Dart_Handle seed_object = HandleError(Dart_GetNativeArgument(arguments, 0));
if (Dart_IsString(seed_object)) {
const char* seed;
HandleError(Dart_StringToCString(seed_object, &seed));
from = seed;
}
num = (int)Dart_GetNativeArgument(arguments, 1);
Dart_SetReturnValue(arguments, HandleError(Dart_NewStringFromCString(sayHello(from, num).c_str())));
}
In Dart, I call the function and pass in the necessary arguments
String sayHello(String from) native "sayHello";
main() {
print(sayHello("Dart"));
}
I was wondering how I could pass in pointers (to a struct I made) instead of just strings and ints as arguments. There are functions in Dart to convert Dart_Handles into Strings and ints but not pointers. What is the internal structure of the Dart_Handle and how would I go about converting it back to a pointer? For example:
Dart code:
String sayHello(info from) native "sayHello";
class info
{
String message;
int num;
}
main() {
info tester = new info();
tester.message = "Dart";
tester.num = 2;
print(sayHello(tester));
}
C Code:
void sayHello(Dart_NativeArguments arguments) {
/*What do I do here to get back a pointe to the struct/class I passed
in as an argument in Dart?*/
}
Your Dart_NativeArguments will consist of just one item, which will be an instance - the instance of the class info that you created with new info(). You can test whether it's an instance with bool Dart_IsInstance(Dart_Handle object). So what you have is an handle to an instance of info. This allows you to access its instance fields (message and num) to get and set them, using Dart_GetField and Dart_SetField.
Dart_Handle instance = Dart_GetNativeArgument(arguments, 0);
Dart_Handle message_handle = Dart_GetField(retobj, NewString("message"));
char* message;
Dart_StringToCString(message_handle, &message);
Dart_Handle number_handle = Dart_GetField(retobj, NewString("num"));
int64_t number;
Dart_IntegerToInt64(number_handle, &number);
// message contains the string, number contains the number
// use them, copy them etc
I know this is just an example, but it might be easier to redefine sayHello to take 2 arguments (a string and an int) rather than passing an object instance. There isn't a way to access the fields of a class in one step, you need to access them individually. Consider these two versions of the Dart code, one passing an object instance and one just the values. The second version is simpler at the Dart and C side (no GetField steps). The first version is more powerful, though, because you could update the fields using SetField, which you couldn't in the second.
class Info {
String message;
int num;
Info(this.message, this.num);
}
version1() {
sayHelloV1(new Info('Dart', 2));
}
version2() {
sayHelloV2('Dart', 2);
}
If your C API requires you to pass in a struct you will have to create that in your C code by copying the values you extract using Dart_IntegerToInt64etc into it, then pass the pointer to your C struct to the API.
If your API is very precise about the packing/padding of the data into the struct, you could use Dart typed_data to pack the Dart types into a ByteData and pass the underlying byte array.

Error: cannot find symbol -- EC=Character.parseChar(JOptionPane.showInputDialog("enter employee code"));

My professor said that we need to input a letter to the dialog box in order for regular, probation etc. to show. I don't know how to resolve this problem. Is there something wrong? I'm new to java.
Here's my code:
import javax.swing.*;
public class EmployeeCode_input
{
public static void main (String[]args)
{
char EC;
EC=Character.parseChar(JOptionPane.showInputDialog("enter employee code"));
if ((EC=="R")&&(EC=="r"))
System.out.println("Regular");
else if((EC=="P")&&(EC=="p"))
System.out.println("Probationing");
else if((EC=="T")&&(EC=="t"))
System.out.println("Trainee");
else if ((EC=="C")&&(EC=="c"))
System.out.println("Contractual");
else
System.out.println("INVALID");
}
}
Character.parseChar is not available in Java.
As chinmay ghag pointed out there is no Character.parseChar in Java. You may use String's charAt() method instead.
Change :
EC=Character.parseChar(JOptionPane.showInputDialog("enter employee code"));
To :
EC=JOptionPane.showInputDialog("enter employee code").charAt(0);
See this for more information: How to convert/parse from String to char in java?
Also if EC is of type char then you shouldn't be comparing char's with strings. ie: EC = 'p' not EC = "p"

Binding a static global causes error in MonoTouch

I started with a functioning bindings project, but I needed to add a global int for a status flag and I can't get it to bind without error. I started with the sample code and can't get this to work.
The code I add to my bindings file is:
[Static]
interface CameraEffects {
[Field ("kCameraEffectsZoomFactorKey", "CameraLibrary")]
NSString ZoomFactorKey { get; }
}
I get three errors:
obj/Debug/ios/PDFExpert/CameraEffects.g.cs(34,94): error CS0117: `MonoTouch.Constants' does not contain a definition for `CameraLibraryLibrary'
obj/Debug/ios/PDFExpert/CameraEffects.g.cs(34,76): error CS1502: The best overloaded method match for `MonoTouch.ObjCRuntime.Dlfcn.dlopen(string, int)' has some invalid arguments
obj/Debug/ios/PDFExpert/CameraEffects.g.cs(34,76): error CS1503: Argument `#1' cannot convert `object' expression to type `string'
If I leave the library off it tried to assign it to another unknown constant. This seems really screwed up as it is strait from the documentation.
I guess this should be bound like this
[Static]
interface CameraEffects {
[Field ("kCameraEffectsZoomFactorKey", "__Internal")]
NSString ZoomFactorKey { get; }
}
This is due to on the final app, the executable and the libxxx.a will be linked and merged together so it should work.
Alex
Another option that allows both assignment and retrieval of the value is to use the internal marshalling that MonoTouch uses. I got this from a Xamarin support person, notice that this is for manipulating an int, but should be a pattern you can use if you get the right marshalling code.
public unsafe static partial class RDPDFGlobal
{
static readonly IntPtr __Internal_libraryHandle = Dlfcn.dlopen (null, 0);
public static int RDPDFFeatures {
get {
return Dlfcn.GetInt32 (__Internal_libraryHandle, "RDPDFKitEnabledFeatures");
}
set {
var indirect = Dlfcn.dlsym (__Internal_libraryHandle, "RDPDFKitEnabledFeatures");
if (indirect == IntPtr.Zero)
throw new Exception ("Field 'RDPDFKitEnabledFeatures' not found.");
Marshal.WriteInt32 (indirect, value);
}
}

Walking through an nsIDOMNodeList

I'm working on a C++ component for Firefox and I'm trying to wrap my mind around XPCOM and all of its parts. It's really confusing so I'm trying to work through it but I'm trying to walk through a page and get all its links. I'm trying to figure out what all the objects do. So if I have this interface:
interface nsIPageSummary : nsISupports {
boolean saveSummary(in nsIDOMDocument document,
out unsigned long numLinks,
out unsigned long numImages);
};
defined in the IDL, the method in my C++ code would look like:
SaveSummary(nsIDOMDocument* inDoc, PRBool* outSuccess)
{
*outSuccess = PR_FALSE;
nsCOMPtr<nsIDOMNodeList> nodeList;
inDoc->GetElementsByTagName(NS_LITERAL_STRING("A"), getter_AddRefs(nodeList));
}
I know the C++ method needs more parameters to match up with the one defined in the interface but I don't understand how all the typing works yet. In terms of the actual list, am I right in understanding that the
inDoc->GetElementsByTagName(NS_LITERAL_STRING("A"), getter_AddRefs(nodeList));
line puts all the "A" tags from the inDoc into the nodeList? And I would just have to walk through nodeList to get them all?
You compile your interface definition using xpidl to get a C++ header file - you can check that file to see how interface definitions are translated. Your method definition should actually look like thit:
nsresult SaveSummary(nsIDOMDocument* inDoc, PRUint32* outNumLinks, PRUint32* outNumImages, PRBool* outSuccess)
I would suggest to use the type PRUint32 instead of the ambiguous unsigned long in the interface definition as well. I would also suggest getting rid of the return value: XPCOM methods always return nsresult which is either NS_OK or an error code, this is enough to indicate success or failure. An error code is automatically translated into an exception when called from JavaScript. And finally I would recommend using lower-case tag names: while it won't matter in HTML (case-insensitive), in an XHTML document only lower-case tag names are accepted. So your interface definition should look like this:
interface nsIPageSummary : nsISupports {
void saveSummary(in nsIDOMDocument document,
out PRUint32 numLinks,
out PRUint32 numImages);
};
And the corresponding implementation:
nsresult
SaveSummary(nsIDOMDocument* inDoc, PRUint32* outNumLinks, PRUint32* outNumImages)
{
nsresult rv;
nsCOMPtr<nsIDOMNodeList> nodeList;
rv = inDoc->GetElementsByTagName(NS_LITERAL_STRING("a"), getter_AddRefs(nodeList));
if (NS_FAILED(rv))
return rv;
rv = nodeList->GetLength(outNumLinks);
if (NS_FAILED(rv))
return rv;
rv = inDoc->GetElementsByTagName(NS_LITERAL_STRING("img"), getter_AddRefs(nodeList));
if (NS_FAILED(rv))
return rv;
rv = nodeList->GetLength(outNumImages);
if (NS_FAILED(rv))
return rv;
return NS_OK;
}

Resources