0

I am trying to understand how I can typecast in Delphi, similar to C/C++.

The C++ code I'm trying to convert is this;

typedef struct tagEXT2_INODE
{
    uint16_t    i_mode;     /* File mode */
    uint16_t    i_uid;      /* Low 16 bits of Owner Uid */
    uint32_t    i_size;     /* Size in bytes */
    uint32_t    i_atime;        /* Access time */
    uint32_t    i_ctime;        /* Creation time */
    uint32_t    i_mtime;        /* Modification time */
    uint32_t    i_dtime;        /* Deletion Time */
    uint16_t    i_gid;      /* Low 16 bits of Group Id */
    uint16_t    i_links_count;  /* Links count */
    uint32_t    i_blocks;       /* Blocks count */
    uint32_t    i_flags;        /* File flags */
    union {
        struct {
            uint32_t  l_i_reserved1;
        } linux1;
        struct {
            uint32_t  h_i_translator;
        } hurd1;
        struct {
            uint32_t  m_i_reserved1;
        } masix1;
    } osd1;             /* OS dependent 1 */
    uint32_t    i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
    uint32_t    i_generation;   /* File version (for NFS) */
    uint32_t    i_file_acl;     /* File ACL */
//    uint32_t  i_dir_acl;      /* Directory ACL */
    uint32_t    i_size_high;            /* This is used store the high 32 bit of file size in large files */
    uint32_t    i_faddr;        /* Fragment address */
    union {
        struct {
            uint8_t l_i_frag;   /* Fragment number */
            uint8_t l_i_fsize;  /* Fragment size */
            uint16_t    i_pad1;
            uint16_t    l_i_uid_high;   /* these 2 fields    */
            uint16_t    l_i_gid_high;   /* were reserved2[0] */
            uint32_t    l_i_reserved2;
        } linux2;
        struct {
            uint8_t h_i_frag;   /* Fragment number */
            uint8_t h_i_fsize;  /* Fragment size */
            uint16_t    h_i_mode_high;
            uint16_t    h_i_uid_high;
            uint16_t    h_i_gid_high;
            uint16_t    h_i_author;
        } hurd2;
        struct {
            uint8_t m_i_frag;   /* Fragment number */
            uint8_t m_i_fsize;  /* Fragment size */
            uint16_t    m_pad1;
            uint32_t    m_i_reserved2[2];
        } masix2;
    } osd2;                 /* OS dependent 2 */
} __attribute__ ((__packed__)) EXT2_INODE;


EXT2_INODE *src;
char *inode_buffer;
int inode_index, ret = 0;

inode_buffer = (char *)malloc(4096);


src = (EXT2_INODE *)(inode_buffer + inode_index);

Could someone explain how this src can be typecasted like this? And how would I do the same operation in Delphi?

Thanks

Edit: Here is my Ext2 iNode Record; Type

  TExt2iNode = Record
    i_mode : Word;
    i_uid : Word;
    i_size : Cardinal;
    i_atime : Cardinal;
    i_ctime : Cardinal;
    i_mtime : Cardinal;
    i_dtimes : Cardinal;
    i_gid : Word;
    i_links_count : Word;
    i_blocks: Cardinal;
    i_flags : Cardinal;
    osd1 : Record
      linux1 : Record
        l_i_reserved1 : Cardinal;
      end;
      hurd1 : Record
        h_i_translator: Cardinal;
      End;
      masix1 : Record
        m_i_reserved1 : Cardinal;
      End;
    End;
    i_block: array [0..EXT2_N_BLOCKS-1] of Cardinal;
    i_generation : Cardinal;
    i_file_acl : Cardinal;
    i_size_high : Cardinal;
    i_faddr : Cardinal;

    osd2 : Record
      Linux2 : Record
        l_i_frag : Byte;
        l_i_fsize : Byte;
        i_pad1 : Word;
        l_i_uid_high : Word;
        l_i_gid_high : Word;
        l_i_reserved2 : Cardinal
      end;
      hurd2 : Record
        h_i_frag : Byte;
        h_i_fsize : Byte;
        h_i_mode_high : Word;
        h_i_uid_high : Word;
        h_i_gid_high : Word;
        h_i_author : Word;
      end;
      masix2 : Record
        m_i_frag:Byte;
        m_i_fsize : Byte;
        m_pad1 : Word;
        m_i_reserved : array[0..1] of Cardinal;
      end;
    end;
  End;

Here is my Ex2 Partition Record;

type 
  Ext2Partition = Class 
    private
      handle: THandle;
      sect_size: Integer;
      total_sectors: Int64;
      relative_sect: Int64;
      linux_name :AnsiString;

      inodes_per_group: integer;
      inode_size: integer;
      block_size: integer;
      totalGRoups: Integer;
      desc : TExt2_Group_Desc;

      last_block : Cardinal;
      inode_buffer : array of AnsiChar;
      root : Ext2File;
      buffercache : TList;
      lvol : LogicalVolume;
    public
      onview, is_valid: boolean;
    published
      Constructor Create(size, offset :int64; ssise: integer; PHandle: THandle);
      function read_inode(inum: Cardinal):Ext2File;
      function readblock(blocknum: cardinal; var buffer: array of AnsiChar):integer;
      function mount():integer;
  End;

Here is my read_inode function where the pointer calculation takes place;

function Ext2Partition.read_inode(inum: Cardinal):Ext2File;
var
  group, index, blknum: cardinal;
  inode_index : integer;
  ret: integer;
  fFile: EXt2File;
  src: TExt2iNode;
begin
  if inum = 0 then
    Result := NIL;

  SetLength(self.inode_buffer, self.block_size);

  group := (inum -1) DIV self.inodes_per_group;

  if group > self.totalGRoups then
  begin
    //ShowMessage('Error reading iNode');
    Result := -1;
  end;

  index := ((inum-1) MOD self.inodes_per_group) * self.inode_size;
  inode_index := (index MOD self.block_size);
  blknum := self.desc.bg_inode_table + (index div self.block_size);

  if blknum <> self.last_block then
    ret := readblock(blknum, self.inode_buffer);

  fFile := TExt2iNode.Create;

  //What goes here?

end;
1
  • That's not typecasting as a class. It's typecasting the content of memory after incrementing a pointer address to a struct (record in Delphi). Commented Feb 6, 2015 at 20:48

1 Answer 1

1

The code allocates a block of memory. Elsewhere, it has determined the offset of an ext2 inode structure somewhere inside that block, given by inode_index. It adds that offset to the start of the block, giving the address of the structure. The code then type-casts the result to tell the compiler that the computed char* address is really the address of that struct type.

Using a literal translation, we'd have the following Delphi declarations:

var
  inode_buffer: PAnsiChar;
  inode_index: Integer;
  src: PExt2_Inode;

Therefore, to assign src, you'd type-cast and add exactly as in the C++ code:

src := PExt2_Inode(inode_buffer + inode_index);

Most Delphi pointer types don't support such pointer arithmetic by default, but PAnsiChar is special.

Using your translation so far, where inode_buffer is an array instead of a pointer to a memory block, you'd instead have this:

src := PExt2_Inode(@inode_buffer[inode_index]);

That indexes the array, and then uses the @ operator to get the address of that array element. (In fact, you could use the same syntax if inode_buffer were my original PAnsiChar type, too.)

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for your input. I've added my Ext2 Partition Record where inode_buffer is being stored. I've used array of AnsiChar.
Is there any benefit to using a Pointer rather than an array of ansichar? Also trying your suggestion, I get a compilation error - Invalid Typecast.
None, as long as you're in control of how and when memory gets allocated. (If you weren't in control, then someone else is allocating memory for you, and then you get whatever you're given, which often will be a simple memory block from malloc or GetMem.) Prefer array of Byte, though. You're not storing text, so Byte is a more appropriate type than Char.
Regarding the invalid typecast, be careful that you're casting to a pointer type. That's what the P prefix in my type name signifies. I've assumed you have a type declaration stating PExt2_Inode = ^TExt2_Inode.
Right, fixed it now. I didn't have a Pointer for the Ext2_Inode record.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.