kaitai_struct
kaitai_struct copied to clipboard
[Java] java.lang.Long cannot be converted to int
Hi,
I'm having an issue when trying to use this Java class: https://formats.kaitai.io/ds_store/java.html
Line 662 returns the following error: incompatible types: java.lang.Long cannot be converted to int
Here is my setup:
- kaitai-struct-compiler:
0.9
- JDK:
openjdk version "17.0.2" 2022-01-18
Let me know if you need any more information.
I’ve also experienced this issue with Java 11. (Seems likely to impact any java version.)
Another reminder that we need to dig much deeper into boxed numeric types in Java.
Anyone know if the ds_store struct has been regenerated following the above mentioned fix? ☝️
@kingthorin:
Anyone know if the ds_store struct has been regenerated following the above mentioned fix? ☝️
It hasn't - all parsers in the format gallery are always built using the latest stable compiler, which is 0.10 at this point. The above fix https://github.com/kaitai-io/kaitai_struct_compiler/commit/604359d63b7d98511828913e206a85f105d3993a is only on the serialization
branch so far, so it must be first merged to master
and then it can appear in a new version (but that isn't likely to happen anytime soon).
But this issue (and pretty much all "type X cannot be converted to Y" problems in user expressions) can in fact be worked around with type casting, if you are blocked by it - in this case, the problem is that
-
block_id
is au4
integer (Java'sint
is signed, so it cannot hold the entire range ofu4
andlong
is used instead) AND -
block_id
is conditional (hasif
- that changes its type to boxed instead of the primitive type), soLong
is used instead of primitivelong
.
Java only supports int
array indices, so the compiler has the (int)
casting of "whatever the subscript expression is" hardcoded (JavaTranslator.scala:102-103
):
override def arraySubscript(container: expr, idx: expr): String =
s"${translate(container)}.get((int) ${translate(idx)})"
And the Long
cannot be converted to int
using (int) ...
directly, as we've seen.
However, if you manually cast block_id
to primitive long
by using a type cast .as<u4>
, it will be translated into .get((int) ((long) ...))
, which will already work. See macos/ds_store.ksy:156-172
:
types:
block_data:
params:
- id: mode
type: u4
seq:
- id: block_id
type: u4
if: mode > 0
- id: record
type: record
instances:
block:
io: _root._io
- pos: _root.buddy_allocator_body.block_addresses[block_id].offset
+ pos: _root.buddy_allocator_body.block_addresses[block_id.as<u4>].offset
type: block
if: mode > 0
As anticipated:
@@ -659,7 +659,7 @@ public class DsStore extends KaitaiStruct {
if (mode() > 0) {
KaitaiStream io = _root()._io();
long _pos = io.pos();
- io.seek(_root().buddyAllocatorBody().blockAddresses().get((int) blockId()).offset());
+ io.seek(_root().buddyAllocatorBody().blockAddresses().get((int) ((long) (blockId()))).offset());
this.block = new Block(io, this, _root);
io.seek(_pos);
}
I guess it makes sense to add this workaround to the official ds_store.ksy
. Even when the compiler will be able to handle it in Java, I assume that C# will have exactly the same problem, because I had to add a bunch of typecasts in the coreldraw_cdr.ksy
spec I'm working on (https://github.com/kaitai-io/coreldraw_cdr.ksy/search?q=C%23&type=commits) to make it compile in C#.
@generalmimon thank you for the very detailed response, I'll see where I can get with it.
Many thanks @generalmimon for your insights!
I just created a PR to apply your fix to my ds_store.ksy
in the format gallery: https://github.com/kaitai-io/kaitai_struct_formats/pull/632