1 /*
2 
3  Package: dyncall
4  Library: dyncall
5  File: dyncall/dyncall_struct.c
6  Description: C interface to compute struct size
7  License:
8 
9    Copyright (c) 2010-2015 Olivier Chafik <olivier.chafik@centraliens.net>
10 
11    Permission to use, copy, modify, and distribute this software for any
12    purpose with or without fee is hereby granted, provided that the above
13    copyright notice and this permission notice appear in all copies.
14 
15    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 
23 */
24 
25 
26 
27 #include "dyncall.h"
28 #include "dyncall_signature.h"
29 #include "dyncall_struct.h"
30 #include "dyncall_alloc.h"
31 #include <stdio.h>
32 #include <assert.h>
33 
34 
dcNewStruct(DCsize fieldCount,DCint alignment)35 DCstruct* dcNewStruct(DCsize fieldCount, DCint alignment)
36 {
37 	DCstruct* s = (DCstruct*)dcAllocMem(sizeof(DCstruct));
38 	s->pCurrentStruct = s;
39 	s->pLastStruct = NULL;
40 	s->nextField = 0;
41 	s->fieldCount = fieldCount;
42 	s->alignment = alignment;
43 	s->size = 0;
44 	s->pFields = (DCfield*)dcAllocMem(fieldCount * sizeof(DCfield));
45 	return s;
46 }
47 
48 
dcStructField(DCstruct * s,DCint type,DCint alignment,DCsize arrayLength)49 void dcStructField(DCstruct* s, DCint type, DCint alignment, DCsize arrayLength)
50 {
51 	DCfield *f;
52 	if (type == DC_SIGCHAR_STRING) {
53 		assert(!"Use dcSubStruct instead !!!");
54 		return;
55 	}
56 	assert(s && s->pCurrentStruct);
57 	assert(s->pCurrentStruct->nextField < (DCint)s->pCurrentStruct->fieldCount);
58 	f = s->pCurrentStruct->pFields + (s->pCurrentStruct->nextField++);
59 	f->type = type;
60 	f->alignment = alignment;
61 	f->arrayLength = arrayLength;
62 	f->pSubStruct = NULL;
63 	switch (type) {
64     	case DC_SIGCHAR_BOOL:       f->size = sizeof(DCbool);     break;
65     	case DC_SIGCHAR_CHAR:
66     	case DC_SIGCHAR_UCHAR:      f->size = sizeof(DCchar);     break;
67     	case DC_SIGCHAR_SHORT:
68     	case DC_SIGCHAR_USHORT:     f->size = sizeof(DCshort);    break;
69     	case DC_SIGCHAR_INT:
70     	case DC_SIGCHAR_UINT:       f->size = sizeof(DCint);      break;
71     	case DC_SIGCHAR_LONG:
72     	case DC_SIGCHAR_ULONG:      f->size = sizeof(DClong);     break;
73     	case DC_SIGCHAR_LONGLONG:
74     	case DC_SIGCHAR_ULONGLONG:  f->size = sizeof(DClonglong); break;
75     	case DC_SIGCHAR_FLOAT:      f->size = sizeof(DCfloat);    break;
76     	case DC_SIGCHAR_DOUBLE:     f->size = sizeof(DCdouble);   break;
77     	case DC_SIGCHAR_POINTER:
78 		case DC_SIGCHAR_STRING:     f->size = sizeof(DCpointer);  break;
79 		default:                    assert(0);
80 	}
81 }
82 
83 
dcSubStruct(DCstruct * s,DCsize fieldCount,DCint alignment,DCsize arrayLength)84 void dcSubStruct(DCstruct* s, DCsize fieldCount, DCint alignment, DCsize arrayLength)
85 {
86 	DCfield *f = s->pCurrentStruct->pFields + (s->pCurrentStruct->nextField++);
87 	f->type = DC_SIGCHAR_STRUCT;
88 	f->arrayLength = arrayLength;
89 	f->alignment = alignment;
90 	f->pSubStruct = dcNewStruct(fieldCount, alignment);
91 	f->pSubStruct->pLastStruct = s->pCurrentStruct;
92 	s->pCurrentStruct = f->pSubStruct;
93 }
94 
95 
dcAlign(DCsize * size,DCsize alignment)96 static void dcAlign(DCsize *size, DCsize alignment)
97 {
98 	DCsize mod = (*size) % alignment;
99 	if (mod) {
100 		DCsize rest = alignment - mod;
101 		(*size) += rest;
102 	}
103 }
104 
105 
dcComputeStructSize(DCstruct * s)106 static void dcComputeStructSize(DCstruct* s)
107 {
108 	DCsize i;
109 	assert(s);
110 
111 	/* compute field sizes and alignments, recurse if needed */
112 	for (i = 0; i < s->fieldCount; i++) {
113 		DCfield *f = s->pFields + i;
114 		DCsize fieldAlignment;
115 		if (f->type == DC_SIGCHAR_STRUCT) {
116 			dcComputeStructSize(f->pSubStruct);
117 			f->size = f->pSubStruct->size;
118 			fieldAlignment = f->pSubStruct->alignment;
119 		} else
120 			fieldAlignment = f->size;
121 
122 		if (!f->alignment)
123 			f->alignment = fieldAlignment;
124 
125 		/* if field alignment > struct alignment, choose former */
126 		if (f->alignment > s->alignment)
127 			s->alignment = f->alignment;
128 
129 		/* if array, it's x times the size */
130 		f->size *= f->arrayLength;
131 
132 		/*printf("FIELD %d, size = %d, alignment = %d\n", (int)i, (int)f->size, (int)f->alignment);@@@*/
133 	}
134 
135 	/* compute overall struct size */
136 	for (i = 0; i < s->fieldCount; i++) {
137 		DCfield *f = s->pFields + i;
138 		dcAlign(&s->size, f->alignment);
139 		s->size += f->size;
140 	}
141 	dcAlign(&s->size, s->alignment);
142 
143 	/*printf("STRUCT size = %d, alignment = %d\n", (int)s->size, (int)s->alignment);@@@*/
144 }
145 
146 
dcCloseStruct(DCstruct * s)147 void dcCloseStruct(DCstruct* s)
148 {
149 	assert(s);
150 	assert(s->pCurrentStruct);
151 	assert(s->pCurrentStruct->nextField == s->pCurrentStruct->fieldCount);
152 	if (!s->pCurrentStruct->pLastStruct) {
153 		dcComputeStructSize(s->pCurrentStruct);
154 	}
155 	s->pCurrentStruct = s->pCurrentStruct->pLastStruct;
156 }
157 
158 
dcFreeStruct(DCstruct * s)159 void dcFreeStruct(DCstruct* s)
160 {
161 	DCsize i;
162 	assert(s);
163 	for (i = 0; i < s->fieldCount; i++) {
164 		DCfield *f = s->pFields + i;
165 		if (f->type == DC_SIGCHAR_STRUCT)
166 			dcFreeStruct(f->pSubStruct);
167 	}
168 	free(s->pFields);
169 	free(s);
170 }
171 
172 
dcStructSize(DCstruct * s)173 DCsize dcStructSize(DCstruct* s)
174 {
175 	assert(!s->pCurrentStruct && "Struct was not closed");
176 	return s->size;
177 }
178 
dcStructAlignment(DCstruct * s)179 DCsize dcStructAlignment(DCstruct* s)
180 {
181 	assert(!s->pCurrentStruct && "Struct was not closed");
182 	return s->alignment;
183 }
184 
185 
dcArgStructUnroll(DCCallVM * vm,DCstruct * s,DCpointer value)186 void dcArgStructUnroll(DCCallVM* vm, DCstruct* s, DCpointer  value)
187 {
188 	DCsize i;
189 	/*printf("UNROLLING STRUCT !\n");@@@*/
190 	assert(s && value);
191 	for (i = 0; i < s->fieldCount; i++) {
192 		DCfield *f = s->pFields + i;
193 		DCpointer p = (char*)value + f->offset;
194 		switch(f->type) {
195 		  case DC_SIGCHAR_STRUCT:
196 		  	dcArgStruct(vm, f->pSubStruct, p);
197 		  	break;
198 		  case DC_SIGCHAR_BOOL:
199 			dcArgBool      (vm, *(DCbool*)p);
200 			break;
201 		  case DC_SIGCHAR_CHAR:
202 		  case DC_SIGCHAR_UCHAR:
203 			dcArgChar      (vm, *(DCchar*)p);
204 			break;
205 		  case DC_SIGCHAR_SHORT:
206 		  case DC_SIGCHAR_USHORT:
207 			dcArgShort     (vm, *(DCshort*)p);
208 			break;
209 		  case DC_SIGCHAR_INT:
210 		  case DC_SIGCHAR_UINT:
211 			dcArgInt       (vm, *(DCint*)p);
212 			break;
213 		  case DC_SIGCHAR_LONG:
214 		  case DC_SIGCHAR_ULONG:
215 			dcArgLong      (vm, *(DCulong*)p);
216 			break;
217 		  case DC_SIGCHAR_LONGLONG:
218 		  case DC_SIGCHAR_ULONGLONG:
219 			dcArgLongLong  (vm, *(DCulonglong*)p);
220 			break;
221 		  case DC_SIGCHAR_FLOAT:
222 			dcArgFloat     (vm, *(DCfloat*)p);
223 			break;
224 		  case DC_SIGCHAR_DOUBLE:
225 			dcArgDouble    (vm, *(DCdouble*)p);
226 			break;
227 		  case DC_SIGCHAR_POINTER:
228 		  case DC_SIGCHAR_STRING:
229 			dcArgPointer   (vm, *(DCpointer**)p);
230 			break;
231 	       default:
232 	       	assert(0);
233 		}
234 	}
235 }
236 
237 
readInt(const char ** ptr)238 static DCint readInt(const char** ptr)
239 {
240 	return strtol(*ptr, (char**)ptr, 10);/*@@@ enough*/
241 }
242 
243 
dcDefineStruct(const char * signature)244 DCstruct* dcDefineStruct(const char* signature)
245 {
246 	DCstruct* s;
247 	const char* ptr = signature;
248 	DCint fieldCount = readInt(&ptr);
249 	s = dcNewStruct(fieldCount, DEFAULT_ALIGNMENT);
250 
251 	while (*ptr) {
252 		char type = *(ptr++);
253 		if (type == DC_SIGCHAR_STRUCT) {
254 			/*dcSubStruct(	@@@*/
255 		} else {
256 			dcStructField(s, type, DEFAULT_ALIGNMENT, readInt(&ptr));
257 		}
258 	}
259 	dcCloseStruct(s);
260 	return s;
261 }
262 
263