[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_idis au4integer (Java'sintis signed, so it cannot hold the entire range ofu4andlongis used instead) AND -
block_idis conditional (hasif- that changes its type to boxed instead of the primitive type), soLongis 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