2002-09-23 22:38:30 +02:00
|
|
|
#
|
|
|
|
# Copyright 2002 Patrik Stridvall
|
|
|
|
#
|
|
|
|
# This library is free software; you can redistribute it and/or
|
|
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
|
|
# License as published by the Free Software Foundation; either
|
|
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This library is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
# Lesser General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
|
|
# License along with this library; if not, write to the Free Software
|
2006-05-18 14:49:52 +02:00
|
|
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2002-09-23 22:38:30 +02:00
|
|
|
#
|
|
|
|
|
|
|
|
package c_type;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
2002-10-09 20:12:02 +02:00
|
|
|
use output qw($output);
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub _refresh($);
|
|
|
|
|
|
|
|
sub new($) {
|
2002-09-23 22:38:30 +02:00
|
|
|
my $proto = shift;
|
|
|
|
my $class = ref($proto) || $proto;
|
|
|
|
my $self = {};
|
|
|
|
bless ($self, $class);
|
|
|
|
|
|
|
|
return $self;
|
|
|
|
}
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
########################################################################
|
|
|
|
# set_find_align_callback
|
|
|
|
#
|
2004-10-26 02:12:21 +02:00
|
|
|
sub set_find_align_callback($$) {
|
2002-10-11 19:53:13 +02:00
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
my $find_align = \${$self->{FIND_ALIGN}};
|
|
|
|
|
|
|
|
$$find_align = shift;
|
|
|
|
}
|
|
|
|
|
2002-11-04 23:40:13 +01:00
|
|
|
########################################################################
|
|
|
|
# set_find_kind_callback
|
|
|
|
#
|
2004-10-26 02:12:21 +02:00
|
|
|
sub set_find_kind_callback($$) {
|
2002-11-04 23:40:13 +01:00
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
my $find_kind = \${$self->{FIND_KIND}};
|
|
|
|
|
|
|
|
$$find_kind = shift;
|
|
|
|
}
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
########################################################################
|
|
|
|
# set_find_size_callback
|
|
|
|
#
|
2004-10-26 02:12:21 +02:00
|
|
|
sub set_find_size_callback($$) {
|
2002-10-11 19:53:13 +02:00
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
my $find_size = \${$self->{FIND_SIZE}};
|
|
|
|
|
|
|
|
$$find_size = shift;
|
|
|
|
}
|
|
|
|
|
2004-08-20 21:33:17 +02:00
|
|
|
########################################################################
|
|
|
|
# set_find_count_callback
|
|
|
|
#
|
2004-10-26 02:12:21 +02:00
|
|
|
sub set_find_count_callback($$) {
|
2004-08-20 21:33:17 +02:00
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
my $find_count = \${$self->{FIND_COUNT}};
|
|
|
|
|
|
|
|
$$find_count = shift;
|
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
|
|
|
|
#
|
|
|
|
# Property setter / getter functions (each does both)
|
|
|
|
#
|
|
|
|
|
|
|
|
sub kind($;$)
|
|
|
|
{
|
2002-09-23 22:38:30 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $kind = \${$self->{KIND}};
|
2002-10-11 19:53:13 +02:00
|
|
|
my $dirty = \${$self->{DIRTY}};
|
2002-09-23 22:38:30 +02:00
|
|
|
|
|
|
|
local $_ = shift;
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
if(defined($_)) { $$kind = $_; $$dirty = 1; }
|
2002-09-23 22:38:30 +02:00
|
|
|
|
2002-11-04 23:40:13 +01:00
|
|
|
if (!defined($$kind)) {
|
|
|
|
$self->_refresh();
|
|
|
|
}
|
|
|
|
|
2002-09-23 22:38:30 +02:00
|
|
|
return $$kind;
|
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
sub _name($;$)
|
|
|
|
{
|
2002-09-23 22:38:30 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $_name = \${$self->{_NAME}};
|
2002-10-11 19:53:13 +02:00
|
|
|
my $dirty = \${$self->{DIRTY}};
|
2002-09-23 22:38:30 +02:00
|
|
|
|
|
|
|
local $_ = shift;
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
if(defined($_)) { $$_name = $_; $$dirty = 1; }
|
2002-09-23 22:38:30 +02:00
|
|
|
|
|
|
|
return $$_name;
|
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
sub name($;$)
|
|
|
|
{
|
2002-09-23 22:38:30 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $name = \${$self->{NAME}};
|
2002-10-11 19:53:13 +02:00
|
|
|
my $dirty = \${$self->{DIRTY}};
|
2002-09-23 22:38:30 +02:00
|
|
|
|
|
|
|
local $_ = shift;
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
if(defined($_)) { $$name = $_; $$dirty = 1; }
|
2002-09-23 22:38:30 +02:00
|
|
|
|
2002-10-01 20:10:54 +02:00
|
|
|
if($$name) {
|
|
|
|
return $$name;
|
|
|
|
} else {
|
|
|
|
my $kind = \${$self->{KIND}};
|
|
|
|
my $_name = \${$self->{_NAME}};
|
|
|
|
|
|
|
|
return "$$kind $$_name";
|
|
|
|
}
|
2002-09-23 22:38:30 +02:00
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
sub pack($;$)
|
|
|
|
{
|
2002-10-02 21:54:14 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $pack = \${$self->{PACK}};
|
2002-10-11 19:53:13 +02:00
|
|
|
my $dirty = \${$self->{DIRTY}};
|
2002-10-02 21:54:14 +02:00
|
|
|
|
|
|
|
local $_ = shift;
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
if(defined($_)) { $$pack = $_; $$dirty = 1; }
|
2002-10-02 21:54:14 +02:00
|
|
|
|
|
|
|
return $$pack;
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub align($) {
|
2002-09-23 22:38:30 +02:00
|
|
|
my $self = shift;
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
my $align = \${$self->{ALIGN}};
|
2002-10-09 20:12:02 +02:00
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
|
|
|
|
|
|
|
return $$align;
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub fields($) {
|
2002-10-11 19:53:13 +02:00
|
|
|
my $self = shift;
|
2002-10-09 20:12:02 +02:00
|
|
|
|
|
|
|
my $count = $self->field_count;
|
2002-09-23 22:38:30 +02:00
|
|
|
|
|
|
|
my @fields = ();
|
|
|
|
for (my $n = 0; $n < $count; $n++) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $field = 'c_type_field'->new($self, $n);
|
|
|
|
push @fields, $field;
|
2002-09-23 22:38:30 +02:00
|
|
|
}
|
|
|
|
return @fields;
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub field_base_sizes($) {
|
2002-10-11 19:53:13 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $field_base_sizes = \${$self->{FIELD_BASE_SIZES}};
|
|
|
|
|
|
|
|
$self->_refresh();
|
|
|
|
|
|
|
|
return $$field_base_sizes;
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub field_aligns($) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $field_aligns = \${$self->{FIELD_ALIGNS}};
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
2002-10-09 20:12:02 +02:00
|
|
|
|
|
|
|
return $$field_aligns;
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub field_count($) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $field_type_names = \${$self->{FIELD_TYPE_NAMES}};
|
|
|
|
|
|
|
|
my @field_type_names = @{$$field_type_names};
|
|
|
|
my $count = scalar(@field_type_names);
|
|
|
|
|
|
|
|
return $count;
|
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
sub field_names($;$)
|
|
|
|
{
|
2002-09-23 22:38:30 +02:00
|
|
|
my $self = shift;
|
2002-10-01 20:10:54 +02:00
|
|
|
my $field_names = \${$self->{FIELD_NAMES}};
|
2002-10-11 19:53:13 +02:00
|
|
|
my $dirty = \${$self->{DIRTY}};
|
2002-09-23 22:38:30 +02:00
|
|
|
|
|
|
|
local $_ = shift;
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
if(defined($_)) { $$field_names = $_; $$dirty = 1; }
|
2002-09-23 22:38:30 +02:00
|
|
|
|
2002-10-01 20:10:54 +02:00
|
|
|
return $$field_names;
|
2002-09-23 22:38:30 +02:00
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub field_offsets($) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $field_offsets = \${$self->{FIELD_OFFSETS}};
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
2002-10-09 20:12:02 +02:00
|
|
|
|
|
|
|
return $$field_offsets;
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub field_sizes($) {
|
2002-09-23 22:38:30 +02:00
|
|
|
my $self = shift;
|
2002-10-09 20:12:02 +02:00
|
|
|
my $field_sizes = \${$self->{FIELD_SIZES}};
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
2002-10-09 20:12:02 +02:00
|
|
|
|
|
|
|
return $$field_sizes;
|
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
sub field_type_names($;$)
|
|
|
|
{
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $field_type_names = \${$self->{FIELD_TYPE_NAMES}};
|
2002-10-11 19:53:13 +02:00
|
|
|
my $dirty = \${$self->{DIRTY}};
|
2002-09-23 22:38:30 +02:00
|
|
|
|
|
|
|
local $_ = shift;
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
if(defined($_)) { $$field_type_names = $_; $$dirty = 1; }
|
2002-10-09 20:12:02 +02:00
|
|
|
|
|
|
|
return $$field_type_names;
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub size($) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
my $size = \${$self->{SIZE}};
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
2002-10-09 20:12:02 +02:00
|
|
|
|
|
|
|
return $$size;
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub _refresh($) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
my $dirty = \${$self->{DIRTY}};
|
|
|
|
|
|
|
|
return if !$$dirty;
|
|
|
|
|
|
|
|
my $find_align = \${$self->{FIND_ALIGN}};
|
2002-11-04 23:40:13 +01:00
|
|
|
my $find_kind = \${$self->{FIND_KIND}};
|
2002-10-11 19:53:13 +02:00
|
|
|
my $find_size = \${$self->{FIND_SIZE}};
|
2004-08-20 21:33:17 +02:00
|
|
|
my $find_count = \${$self->{FIND_COUNT}};
|
2002-10-11 19:53:13 +02:00
|
|
|
|
|
|
|
my $align = \${$self->{ALIGN}};
|
|
|
|
my $kind = \${$self->{KIND}};
|
|
|
|
my $size = \${$self->{SIZE}};
|
2002-10-09 20:12:02 +02:00
|
|
|
my $field_aligns = \${$self->{FIELD_ALIGNS}};
|
2002-10-11 19:53:13 +02:00
|
|
|
my $field_base_sizes = \${$self->{FIELD_BASE_SIZES}};
|
2002-10-09 20:12:02 +02:00
|
|
|
my $field_offsets = \${$self->{FIELD_OFFSETS}};
|
|
|
|
my $field_sizes = \${$self->{FIELD_SIZES}};
|
|
|
|
|
|
|
|
my $pack = $self->pack;
|
2004-05-04 02:38:27 +02:00
|
|
|
$pack = 8 if !defined($pack);
|
2002-10-09 20:12:02 +02:00
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
my $max_field_align = 0;
|
|
|
|
|
2002-10-09 20:12:02 +02:00
|
|
|
my $offset = 0;
|
2004-08-20 21:33:17 +02:00
|
|
|
my $bitfield_size = 0;
|
|
|
|
my $bitfield_bits = 0;
|
2002-10-09 20:12:02 +02:00
|
|
|
|
|
|
|
my $n = 0;
|
|
|
|
foreach my $field ($self->fields) {
|
|
|
|
my $type_name = $field->type_name;
|
|
|
|
|
2004-08-20 21:33:17 +02:00
|
|
|
my $bits;
|
|
|
|
my $count;
|
|
|
|
if ($type_name =~ s/^(.*?)\s*(?:\[\s*(.*?)\s*\]|:(\d+))?$/$1/)
|
|
|
|
{
|
|
|
|
$count = $2;
|
|
|
|
$bits = $3;
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
2004-08-20 21:33:17 +02:00
|
|
|
my $declspec_align;
|
|
|
|
if ($type_name =~ s/\s+DECLSPEC_ALIGN\((\d+)\)//)
|
|
|
|
{
|
|
|
|
$declspec_align=$1;
|
|
|
|
}
|
|
|
|
my $base_size = &$$find_size($type_name);
|
|
|
|
my $type_size=$base_size;
|
|
|
|
if (defined $count)
|
|
|
|
{
|
|
|
|
$count=&$$find_count($count) if ($count !~ /^\d+$/);
|
|
|
|
if (!defined $count)
|
|
|
|
{
|
|
|
|
$type_size=undef;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$type_size *= int($count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($bitfield_size != 0)
|
|
|
|
{
|
|
|
|
if (($type_name eq "" and defined $bits and $bits == 0) or
|
|
|
|
(defined $type_size and $bitfield_size != $type_size) or
|
|
|
|
!defined $bits or
|
|
|
|
$bitfield_bits + $bits > 8 * $bitfield_size)
|
|
|
|
{
|
|
|
|
# This marks the end of the previous bitfield
|
|
|
|
$bitfield_size=0;
|
|
|
|
$bitfield_bits=0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$bitfield_bits+=$bits;
|
|
|
|
$n++;
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$$align = &$$find_align($type_name);
|
|
|
|
$$align=$declspec_align if (defined $declspec_align);
|
|
|
|
|
|
|
|
if (defined $$align)
|
|
|
|
{
|
|
|
|
$$align = $pack if $$align > $pack;
|
|
|
|
$max_field_align = $$align if $$align > $max_field_align;
|
|
|
|
|
|
|
|
if ($offset % $$align != 0) {
|
|
|
|
$offset = (int($offset / $$align) + 1) * $$align;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($$kind !~ /^(?:struct|union)$/)
|
|
|
|
{
|
|
|
|
$$kind = &$$find_kind($type_name) || "";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$type_size)
|
|
|
|
{
|
|
|
|
$$align = undef;
|
|
|
|
$$size = undef;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$$$field_aligns[$n] = $$align;
|
|
|
|
$$$field_base_sizes[$n] = $base_size;
|
|
|
|
$$$field_offsets[$n] = $offset;
|
|
|
|
$$$field_sizes[$n] = $type_size;
|
|
|
|
$offset += $type_size;
|
|
|
|
|
|
|
|
if ($bits)
|
|
|
|
{
|
|
|
|
$bitfield_size=$type_size;
|
|
|
|
$bitfield_bits=$bits;
|
|
|
|
}
|
2002-10-09 20:12:02 +02:00
|
|
|
$n++;
|
|
|
|
}
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
$$align = $pack;
|
|
|
|
$$align = $max_field_align if $max_field_align < $pack;
|
|
|
|
|
2002-10-09 20:12:02 +02:00
|
|
|
$$size = $offset;
|
2002-10-11 19:53:13 +02:00
|
|
|
if ($$kind =~ /^(?:struct|union)$/) {
|
|
|
|
if ($$size % $$align != 0) {
|
|
|
|
$$size = (int($$size / $$align) + 1) * $$align;
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
}
|
2002-10-11 19:53:13 +02:00
|
|
|
|
|
|
|
$$dirty = 0;
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
package c_type_field;
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub new($$$) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $proto = shift;
|
|
|
|
my $class = ref($proto) || $proto;
|
|
|
|
my $self = {};
|
|
|
|
bless ($self, $class);
|
|
|
|
|
|
|
|
my $type = \${$self->{TYPE}};
|
|
|
|
my $number = \${$self->{NUMBER}};
|
|
|
|
|
|
|
|
$$type = shift;
|
|
|
|
$$number = shift;
|
|
|
|
|
|
|
|
return $self;
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub align($) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $type = \${$self->{TYPE}};
|
|
|
|
my $number = \${$self->{NUMBER}};
|
|
|
|
|
|
|
|
my $field_aligns = $$type->field_aligns;
|
|
|
|
|
|
|
|
return $$field_aligns[$$number];
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub base_size($) {
|
2002-10-11 19:53:13 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $type = \${$self->{TYPE}};
|
|
|
|
my $number = \${$self->{NUMBER}};
|
|
|
|
|
|
|
|
my $field_base_sizes = $$type->field_base_sizes;
|
|
|
|
|
|
|
|
return $$field_base_sizes[$$number];
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub name($) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $type = \${$self->{TYPE}};
|
|
|
|
my $number = \${$self->{NUMBER}};
|
|
|
|
|
|
|
|
my $field_names = $$type->field_names;
|
|
|
|
|
|
|
|
return $$field_names[$$number];
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub offset($) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $type = \${$self->{TYPE}};
|
|
|
|
my $number = \${$self->{NUMBER}};
|
|
|
|
|
|
|
|
my $field_offsets = $$type->field_offsets;
|
|
|
|
|
|
|
|
return $$field_offsets[$$number];
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub size($) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $type = \${$self->{TYPE}};
|
|
|
|
my $number = \${$self->{NUMBER}};
|
|
|
|
|
|
|
|
my $field_sizes = $$type->field_sizes;
|
|
|
|
|
|
|
|
return $$field_sizes[$$number];
|
|
|
|
}
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub type_name($) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $self = shift;
|
|
|
|
my $type = \${$self->{TYPE}};
|
|
|
|
my $number = \${$self->{NUMBER}};
|
|
|
|
|
|
|
|
my $field_type_names = $$type->field_type_names;
|
2002-09-23 22:38:30 +02:00
|
|
|
|
2002-10-09 20:12:02 +02:00
|
|
|
return $$field_type_names[$$number];
|
2002-09-23 22:38:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
1;
|