tagged release 0.6.4
[parrot.git] / languages / dotnet / pmc / dotnetsignature.pmc
blob2bb868f653cdb6eff6b947fd310cee78c9dcb84c
1 /*
2  * $Id$
3  * Copyright (C) 2006-2008, The Perl Foundation.
4  */
6 /* .NET CLI Signature PMC */
9 #include "parrot/extend.h"
10 #include "tableinfo.h"
11 #include "structures.h"
14 pmclass DotNetSignature dynpmc group dotnet {
16     /* Instance initialization. We need a custom destroy. */
17     void init()
18     {
19         PObj_active_destroy_SET(SELF);
20         PMC_struct_val(SELF) = NULL;
21     }
24     /* Destructor. */
25     void destroy()
26     {
27         /* Cleanup any memory we're using. */
28         if (PMC_struct_val(SELF)) {
29             dotnet_signature *sig = (dotnet_signature *)PMC_struct_val(SELF);
31             if (sig->data)
32                 mem_sys_free(sig->data);
34             mem_sys_free(sig);
35             PMC_struct_val(SELF) = NULL;
36         }
37     }
40     /* set_string_native copies the data held in the string to the internal
41        blob data buffer so we can easily walk over it. */
42     void set_string_native(STRING* s)
43     {
44         dotnet_signature *sig = (dotnet_signature *)PMC_struct_val(SELF);
46         /* Do we have a struct already allocated? */
47         if (sig != NULL)
48         {
49             /* Yes; free up old string. */
50             if (sig->data)
51                 free(sig->data);
52         }
53         else
54         {
55             /* No; need to allocate a new structure. */
56             sig                  = mem_allocate_zeroed_typed(dotnet_signature);
57             PMC_struct_val(SELF) = sig;
58         }
60         /* Get blob data and its size and reset current position. */
61         sig->data      = string_to_cstring(INTERP, s);
62         sig->data_size = string_length(INTERP, s);
63         sig->cur_pos   = 0;
64     }
67     /* Read an unsigned 8-bit integer. */
68     METHOD INTVAL read_uint8()
69     {
70         dotnet_signature *sig = (dotnet_signature *)PMC_struct_val(SELF);
71         INTVAL            result;
73         /* Handle cases where we've an invalid PMC. */
74         if (!sig || !sig->data)
75             real_exception(INTERP, NULL, E_StandardError,
76                "Invalid DotNetSignature PMC");
78         /* Ensure we won't read past the end. */
79         if (sig->cur_pos >= sig->data_size)
80             real_exception(INTERP, NULL, E_StandardError,
81                "Read past end of signature");
83         /* Otherwise read the value. */
84         result = (INTVAL)sig->data[sig->cur_pos];
85         sig->cur_pos++;
86         RETURN(INTVAL result);
87     }
90     /* Read a compressed integer. */
91     METHOD INTVAL read_compressed()
92     {
93         dotnet_signature *sig = (dotnet_signature *)PMC_struct_val(SELF);
94         INTVAL val;
95         unsigned char b1, b2, b3, b4;
97         /* Handle cases where we've an invalid PMC. */
98         if (!sig || !sig->data)
99             real_exception(INTERP, NULL, E_StandardError,
100                "Invalid DotNetSignature PMC");
102         /* Check first byte read is OK. */
103         if (sig->cur_pos >= sig->data_size)
104             real_exception(INTERP, NULL, E_StandardError,
105                "Read past end of signature");
107         /* Read first byte and decide if it's a single encoded byte (top bit
108            clear). */
109         b1 = sig->data[sig->cur_pos];
111         if ((b1 & 0x80) == 0)
112         {
113             val = b1;
114             sig->cur_pos++;
115         }
117         /* Is it a 2 byte integer (top bits 10)? */
118         else if ((b1 & 0x80) != 0 && (b1 & 0x40) == 0)
119         {
120             /* Check we can read 2 bytes. */
121             if (sig->cur_pos + 1 >= sig->data_size)
122                 real_exception(INTERP, NULL, E_StandardError,
123                     "Read past end of signature");
125             /* Read second byte and make value. */
126             b2  = sig->data[sig->cur_pos + 1];
127             val = ((b1 & 0x3F) << 8) | b2;
128             sig->cur_pos += 2;
129         }
131         /* Is it a 4 byte integer? (top bits 110)? */
132         else if ((b1 & 0x80) != 0 && (b1 & 0x40) != 0 && (b1 & 0x20) == 0) {
133             /* Check we can read 4 bytes. */
134             if (sig->cur_pos + 3 >= sig->data_size)
135                 real_exception(INTERP, NULL, E_StandardError,
136                     "Read past end of signature");
138             /* Read remaining bytes and make value. */
139             b2 = sig->data[sig->cur_pos + 1];
140             b3 = sig->data[sig->cur_pos + 2];
141             b4 = sig->data[sig->cur_pos + 3];
142             val = ((b1 & 0x1F) << 24) | (b2 << 16) | (b3 << 8) | b4;
143             sig->cur_pos += 4;
144         }
146         /* Otherwise, it's a null byte. RT #48128 Need special handling? */
147         else {
148             val = 0;
149             sig->cur_pos++;
150         }
152         /* Return the value. */
153         RETURN(INTVAL val);
154     }
159  * Local variables:
160  *   c-file-style: "parrot"
161  * End:
162  * vim: expandtab shiftwidth=4:
163  */