# Examples of Pyhidra-specific functionality
# @category: Examples.Python


# we can import java libraries just as if they were python libraries
from java.util import LinkedList

# and then use them like they are natural classes
java_list = LinkedList([1,2,3])
print(f"linked list object class: {java_list.__class__}")

# importing and using Ghidra modules is the same
from ghidra.program.flatapi import FlatProgramAPI
print(f"max references to a flat program api: {FlatProgramAPI.MAX_REFERENCES_TO}")

# we can also do normal python-ish things on our Java objects, like:
# indexing
print(f"first element of the list: {java_list[0]}")

# slicing
print(f"first two elements of the list: {java_list[0:2]}")

# list comprehension
java_list_double = [i * 2 for i in java_list]
print(f"list comprehension result: {java_list_double}")

# automatic calls to getters
print(f"current program name: {currentProgram.name}") # calls currentProgram.getName()

# here's an example of how this stuff might come in handy with Ghidra:
print('current program memory blocks:\n')
for block in currentProgram.memory.blocks:
    print(block.name)


# many Ghidra functions need a Java-native array to pass or receive values
# JPype provides objects of JByte, JChar, etc. to meet this need
# this example demonstrates how you would create an array of bytes to get
# the first 10 bytes of memory from the .text section

# we need this import to get at the helper classes
import jpype

# get the block we need
block = currentProgram.memory.getBlock('.text')
if block:
    # the verbose way of getting the array
    byte_array_maker = jpype.JArray(jpype.JByte)
    byte_array = byte_array_maker(10)

    # we also could have taken a shortcut with just:
    # byte_array = jpype.JByte[10]

    # let's have a look at our new object
    print(f"array class: {byte_array.__class__}")
    # will be <java class 'byte[]'>
    print(f"array length: {len(byte_array)}")

    # we can now use this array wherever a Java method requires a byte[] type
    # the signature of getBytes is getBytes(Address addr, byte[] b)
    block.getBytes(block.start, byte_array)

    # after the call, we can get the bytes out as desired
    # we just put them in a list comprehension here
    print(f"first 10 bytes of .text: {['%#x' % ((b+256)%256) for b in byte_array]}")

else:
    print('no block named .text in this program.')

# see the user manual of JPype for more details on interoperability:
# https://jpype.readthedocs.io/en/latest/userguide.html
