1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
12 #include "sjme/nvm/classy.h"
13 #include "sjme/debug.h"
14 #include "sjme/cleanup.h"
16 /** The magic number for classes. */
17 #define SJME_CLASS_MAGIC INT32_C(0xCAFEBABE)
19 /** CLDC 1.1 max version (JSR 30). */
20 #define SJME_CLASS_CLDC_1_0_MAX INT32_C(3080191)
22 /** CLDC 1.1 max version. (JSR 139). */
23 #define SJME_CLASS_CLDC_1_1_MAX INT32_C(3342335)
25 /** CLDC 8 max version. */
26 #define SJME_CLASS_CLDC_1_8_MAX INT32_C(3407872)
29 #define SJME_CLASS_ACC_PUBLIC INT16_C(0x0001)
32 #define SJME_CLASS_ACC_PRIVATE INT16_C(0x0002)
35 #define SJME_CLASS_ACC_PROTECTED INT16_C(0x0004)
38 #define SJME_CLASS_ACC_STATIC INT16_C(0x0008)
40 /** Final class or member. */
41 #define SJME_CLASS_ACC_FINAL INT16_C(0x0010)
43 /** Alternative @c invokesuper logic. */
44 #define SJME_CLASS_ACC_SUPER INT16_C(0x0020)
46 /** Synchronized method. */
47 #define SJME_CLASS_ACC_SYNCHRONIZED INT16_C(0x0020)
50 #define SJME_CLASS_ACC_BRIDGE INT16_C(0x0040)
52 /** Variable arguments. */
53 #define SJME_CLASS_ACC_VARARGS INT16_C(0x0080)
56 #define SJME_CLASS_ACC_NATIVE INT16_C(0x0100)
58 /** Class is an interface. */
59 #define SJME_CLASS_ACC_INTERFACE INT16_C(0x0200)
61 /** Abstract class or method. */
62 #define SJME_CLASS_ACC_ABSTRACT INT16_C(0x0400)
64 /** Strict floating point method. */
65 #define SJME_CLASS_ACC_STRICTFP INT16_C(0x0800)
67 /** Synthetic class or member. */
68 #define SJME_CLASS_ACC_SYNTHETIC INT16_C(0x1000)
70 /** Class is an annotation. */
71 #define SJME_CLASS_ACC_ANNOTATION INT16_C(0x2000)
73 /** Class is an enum. */
74 #define SJME_CLASS_ACC_ENUM INT16_C(0x4000)
76 static sjme_errorCode
sjme_class_readPoolRefIndex(
77 sjme_attrInNotNull sjme_stream_input inStream
,
78 sjme_attrInNotNull sjme_class_poolInfo inClassPool
,
79 sjme_attrInPositiveNonZero sjme_class_poolType desireType
,
80 sjme_attrInValue sjme_jboolean canNull
,
81 sjme_attrOutNotNull sjme_class_poolEntry
** outEntry
)
85 sjme_class_poolEntry
* result
;
87 if (inStream
== NULL
|| inClassPool
== NULL
|| outEntry
== NULL
)
88 return SJME_ERROR_NULL_ARGUMENTS
;
92 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
94 return sjme_error_default(error
);
96 /* Not a valid index? */
97 if (index
<= 0 || index
>= inClassPool
->pool
->length
)
98 return SJME_ERROR_INVALID_CLASS_POOL_INDEX
;
100 /* Must be the desired type. */
101 result
= &inClassPool
->pool
->elements
[index
];
102 if (result
->type
!= desireType
)
103 return SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE
;
107 return SJME_ERROR_NONE
;
110 static const sjme_class_parseAttributeHandlerInfo sjme_class_classAttr
[] =
115 static sjme_errorCode
sjme_class_classFlagsParse(
116 sjme_attrInNotNull sjme_stream_input inStream
,
117 sjme_attrOutNotNull sjme_class_classFlags
* outFlags
)
119 sjme_errorCode error
;
120 sjme_jshort rawFlags
;
122 if (inStream
== NULL
|| outFlags
== NULL
)
123 return SJME_ERROR_NULL_ARGUMENTS
;
127 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
128 inStream
, &rawFlags
)) || rawFlags
< 0)
129 return sjme_error_default(error
);
131 /* Translate to bitfield. */
132 if ((rawFlags
& SJME_CLASS_ACC_PUBLIC
) != 0)
133 outFlags
->access
.public = SJME_JNI_TRUE
;
134 if ((rawFlags
& SJME_CLASS_ACC_FINAL
) != 0)
135 outFlags
->final
= SJME_JNI_TRUE
;
136 if ((rawFlags
& SJME_CLASS_ACC_SUPER
) != 0)
137 outFlags
->super
= SJME_JNI_TRUE
;
138 if ((rawFlags
& SJME_CLASS_ACC_INTERFACE
) != 0)
139 outFlags
->interface
= SJME_JNI_TRUE
;
140 if ((rawFlags
& SJME_CLASS_ACC_ABSTRACT
) != 0)
141 outFlags
->abstract
= SJME_JNI_TRUE
;
142 if ((rawFlags
& SJME_CLASS_ACC_SYNTHETIC
) != 0)
143 outFlags
->synthetic
= SJME_JNI_TRUE
;
144 if ((rawFlags
& SJME_CLASS_ACC_ANNOTATION
) != 0)
145 outFlags
->annotation
= SJME_JNI_TRUE
;
146 if ((rawFlags
& SJME_CLASS_ACC_ENUM
) != 0)
147 outFlags
->enumeration
= SJME_JNI_TRUE
;
149 /* Cannot be abstract and final. */
150 /* Annotation must be an interface. */
151 /* Interface must be abstract and not final, super, or enum */
152 if ((outFlags
->abstract
&& outFlags
->final
) ||
153 (outFlags
->annotation
&& !outFlags
->interface
) ||
154 (outFlags
->interface
&& (!outFlags
->abstract
||
155 outFlags
->final
|| outFlags
->super
|| outFlags
->enumeration
)))
156 return SJME_ERROR_INVALID_CLASS_FLAGS
;
159 return SJME_ERROR_NONE
;
162 static sjme_errorCode
sjme_class_codeAttrLineNumberTable(
163 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
164 sjme_attrInNotNull sjme_class_poolInfo inConstPool
,
165 sjme_attrInNotNull sjme_stringPool inStringPool
,
166 sjme_attrInNotNull sjme_pointer context
,
167 sjme_attrInNotNull sjme_lpcstr attrName
,
168 sjme_attrInNotNullBuf(attrLen
) sjme_pointer attrData
,
169 sjme_attrInPositive sjme_jint attrLen
)
171 if (inPool
== NULL
|| inConstPool
== NULL
|| inStringPool
== NULL
||
172 context
== NULL
|| attrName
== NULL
|| attrData
== NULL
)
173 return SJME_ERROR_NULL_ARGUMENTS
;
176 return SJME_ERROR_NOT_IMPLEMENTED
;
179 static sjme_errorCode
sjme_class_codeAttrStackMap(
180 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
181 sjme_attrInNotNull sjme_class_poolInfo inConstPool
,
182 sjme_attrInNotNull sjme_stringPool inStringPool
,
183 sjme_attrInNotNull sjme_pointer context
,
184 sjme_attrInNotNull sjme_lpcstr attrName
,
185 sjme_attrInNotNullBuf(attrLen
) sjme_pointer attrData
,
186 sjme_attrInPositive sjme_jint attrLen
)
188 if (inPool
== NULL
|| inConstPool
== NULL
|| inStringPool
== NULL
||
189 context
== NULL
|| attrName
== NULL
|| attrData
== NULL
)
190 return SJME_ERROR_NULL_ARGUMENTS
;
193 return SJME_ERROR_NOT_IMPLEMENTED
;
196 static sjme_errorCode
sjme_class_codeAttrStackMapTable(
197 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
198 sjme_attrInNotNull sjme_class_poolInfo inConstPool
,
199 sjme_attrInNotNull sjme_stringPool inStringPool
,
200 sjme_attrInNotNull sjme_pointer context
,
201 sjme_attrInNotNull sjme_lpcstr attrName
,
202 sjme_attrInNotNullBuf(attrLen
) sjme_pointer attrData
,
203 sjme_attrInPositive sjme_jint attrLen
)
205 if (inPool
== NULL
|| inConstPool
== NULL
|| inStringPool
== NULL
||
206 context
== NULL
|| attrName
== NULL
|| attrData
== NULL
)
207 return SJME_ERROR_NULL_ARGUMENTS
;
210 return SJME_ERROR_NOT_IMPLEMENTED
;
213 static const sjme_class_parseAttributeHandlerInfo sjme_class_codeAttr
[] =
216 sjme_class_codeAttrLineNumberTable
},
218 sjme_class_codeAttrStackMap
},
220 sjme_class_codeAttrStackMapTable
},
224 static sjme_errorCode
sjme_class_fieldAttrConstantValue(
225 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
226 sjme_attrInNotNull sjme_class_poolInfo inConstPool
,
227 sjme_attrInNotNull sjme_stringPool inStringPool
,
228 sjme_attrInNotNull sjme_pointer context
,
229 sjme_attrInNotNull sjme_lpcstr attrName
,
230 sjme_attrInNotNullBuf(attrLen
) sjme_pointer attrData
,
231 sjme_attrInPositive sjme_jint attrLen
)
233 if (inPool
== NULL
|| inConstPool
== NULL
|| inStringPool
== NULL
||
234 context
== NULL
|| attrName
== NULL
|| attrData
== NULL
)
235 return SJME_ERROR_NULL_ARGUMENTS
;
238 return SJME_ERROR_NOT_IMPLEMENTED
;
241 static const sjme_class_parseAttributeHandlerInfo sjme_class_fieldAttr
[] =
243 {"ConstantValue", sjme_class_fieldAttrConstantValue
},
247 static sjme_errorCode
sjme_class_methodAttrCode(
248 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
249 sjme_attrInNotNull sjme_class_poolInfo inConstPool
,
250 sjme_attrInNotNull sjme_stringPool inStringPool
,
251 sjme_attrInNotNull sjme_pointer context
,
252 sjme_attrInNotNull sjme_lpcstr attrName
,
253 sjme_attrInNotNullBuf(attrLen
) sjme_pointer attrData
,
254 sjme_attrInPositive sjme_jint attrLen
)
256 if (inPool
== NULL
|| inConstPool
== NULL
|| inStringPool
== NULL
||
257 context
== NULL
|| attrName
== NULL
|| attrData
== NULL
)
258 return SJME_ERROR_NULL_ARGUMENTS
;
261 return SJME_ERROR_NOT_IMPLEMENTED
;
264 static const sjme_class_parseAttributeHandlerInfo sjme_class_methodAttr
[] =
266 {"Code", sjme_class_methodAttrCode
},
270 static sjme_errorCode
sjme_class_methodFlagsParse(
271 sjme_attrInNotNull sjme_stream_input inStream
,
272 sjme_attrOutNotNull sjme_class_methodFlags
* outFlags
)
274 sjme_errorCode error
;
275 sjme_jshort rawFlags
;
277 if (inStream
== NULL
|| outFlags
== NULL
)
278 return SJME_ERROR_NULL_ARGUMENTS
;
282 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
283 inStream
, &rawFlags
)) || rawFlags
< 0)
284 return sjme_error_default(error
);
286 /* Translate to bitfield. */
287 if ((rawFlags
& SJME_CLASS_ACC_PUBLIC
) != 0)
288 outFlags
->member
.access
.public = SJME_JNI_TRUE
;
289 if ((rawFlags
& SJME_CLASS_ACC_PRIVATE
) != 0)
290 outFlags
->member
.access
.private = SJME_JNI_TRUE
;
291 if ((rawFlags
& SJME_CLASS_ACC_PROTECTED
) != 0)
292 outFlags
->member
.access
.protected = SJME_JNI_TRUE
;
293 if ((rawFlags
& SJME_CLASS_ACC_STATIC
) != 0)
294 outFlags
->member
.isStatic
= SJME_JNI_TRUE
;
295 if ((rawFlags
& SJME_CLASS_ACC_FINAL
) != 0)
296 outFlags
->member
.final
= SJME_JNI_TRUE
;
297 if ((rawFlags
& SJME_CLASS_ACC_SYNCHRONIZED
) != 0)
298 outFlags
->synchronized
= SJME_JNI_TRUE
;
299 if ((rawFlags
& SJME_CLASS_ACC_BRIDGE
) != 0)
300 outFlags
->bridge
= SJME_JNI_TRUE
;
301 if ((rawFlags
& SJME_CLASS_ACC_VARARGS
) != 0)
302 outFlags
->varargs
= SJME_JNI_TRUE
;
303 if ((rawFlags
& SJME_CLASS_ACC_NATIVE
) != 0)
304 outFlags
->native
= SJME_JNI_TRUE
;
305 if ((rawFlags
& SJME_CLASS_ACC_ABSTRACT
) != 0)
306 outFlags
->abstract
= SJME_JNI_TRUE
;
307 if ((rawFlags
& SJME_CLASS_ACC_STRICTFP
) != 0)
308 outFlags
->strictfp
= SJME_JNI_TRUE
;
309 if ((rawFlags
& SJME_CLASS_ACC_SYNTHETIC
) != 0)
310 outFlags
->member
.synthetic
= SJME_JNI_TRUE
;
312 /* Can only have a single access mode. */
313 /* Abstract cannot be final, private, static, strict, or synchronized. */
314 if (((outFlags
->member
.access
.public +
315 outFlags
->member
.access
.protected +
316 outFlags
->member
.access
.private) > 1) ||
317 (outFlags
->abstract
&& (outFlags
->member
.final
||
318 outFlags
->native
|| outFlags
->member
.access
.private ||
319 outFlags
->member
.isStatic
|| outFlags
->strictfp
||
320 outFlags
->synchronized
)))
321 return SJME_ERROR_INVALID_METHOD_FLAGS
;
324 return SJME_ERROR_NONE
;
327 static sjme_errorCode
sjme_class_parseAttribute(
328 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
329 sjme_attrInNotNull sjme_stream_input inStream
,
330 sjme_attrInNotNull sjme_class_poolInfo inConstPool
,
331 sjme_attrInNotNull sjme_stringPool inStringPool
,
332 sjme_attrInNotNull
const sjme_class_parseAttributeHandlerInfo
* handlers
,
333 sjme_attrInNotNull sjme_pointer context
,
334 sjme_attrInNotNull sjme_lpcstr attrName
,
335 sjme_attrInPositive sjme_jint attrLen
)
337 sjme_errorCode error
;
338 sjme_jubyte
* attrData
;
340 sjme_class_parseAttributeHandlerInfo
* at
;
342 if (inPool
== NULL
|| inStream
== NULL
|| inConstPool
== NULL
||
343 inStringPool
== NULL
|| handlers
== NULL
|| context
== NULL
||
345 return SJME_ERROR_NULL_ARGUMENTS
;
348 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
350 /* Allocate buffer to read in the data. */
351 attrData
= sjme_alloca(attrLen
);
352 if (attrData
== NULL
)
353 return SJME_ERROR_OUT_OF_MEMORY
;
354 memset(attrData
, 0, attrLen
);
356 /* Read in everything. */
358 if (sjme_error_is(error
= sjme_stream_inputReadFully(
359 inStream
, &readCount
, attrData
, attrLen
)) ||
361 return sjme_error_default(error
);
363 /* Find and call handler for this. */
364 for (at
= handlers
; at
->name
!= NULL
&& at
->handler
!= NULL
; at
++)
365 if (0 == strcmp(at
->name
, attrName
))
366 return at
->handler(inPool
, inConstPool
, inStringPool
, context
,
367 attrName
, attrData
, attrLen
);
369 #if defined(SJME_CONFIG_DEBUG)
371 sjme_message("No handler for attribute %s.", attrName
);
374 /* None found, so ignore it. */
375 return SJME_ERROR_NONE
;
378 sjme_errorCode
sjme_class_parse(
379 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
380 sjme_attrInNotNull sjme_stream_input inStream
,
381 sjme_attrInNotNull sjme_stringPool inStringPool
,
382 sjme_attrOutNotNull sjme_class_info
* outClass
)
384 sjme_errorCode error
;
385 sjme_jint magic
, fullVersion
, i
;
386 sjme_jshort major
, minor
, interfaceCount
, fieldCount
, methodCount
;
387 sjme_class_version actualVersion
;
388 sjme_class_poolInfo pool
;
389 sjme_class_info result
;
390 sjme_class_poolEntry
* thisName
;
391 sjme_class_poolEntry
* superName
;
392 sjme_class_poolEntry
* interfaceName
;
393 sjme_list_sjme_stringPool_string
* interfaceNames
;
394 sjme_list_sjme_class_fieldInfo
* fields
;
395 sjme_list_sjme_class_methodInfo
* methods
;
397 if (inPool
== NULL
|| inStream
== NULL
|| inStringPool
== NULL
||
399 return SJME_ERROR_NONE
;
401 /* Make sure we can actually allocate the resultant class. */
403 if (sjme_error_is(error
= sjme_alloc_weakNew(inPool
,
404 sizeof(*result
), NULL
, NULL
,
405 (sjme_pointer
*)&result
, NULL
)) || result
== NULL
)
406 goto fail_allocResult
;
409 if (sjme_error_is(error
= sjme_nvm_initCommon(
410 SJME_AS_NVM_COMMON(result
),
411 SJME_NVM_STRUCT_CLASS_INFO
)))
412 goto fail_initResult
;
414 /* Read in magic number. */
416 if (sjme_error_is(error
= sjme_stream_inputReadValueJI(
420 /* It must be valid! */
421 if (magic
!= SJME_CLASS_MAGIC
)
423 error
= SJME_ERROR_INVALID_CLASS_MAGIC
;
427 /* Read in version info. */
429 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
434 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
438 /* Compose and find matching version. */
439 fullVersion
= (major
<< 16) | (minor
& 0xFFFF);
440 if (fullVersion
>= SJME_CLASS_CLDC_1_0
&&
441 fullVersion
<= SJME_CLASS_CLDC_1_0_MAX
)
442 actualVersion
= SJME_CLASS_CLDC_1_0
;
443 else if (fullVersion
>= SJME_CLASS_CLDC_1_1
&&
444 fullVersion
<= SJME_CLASS_CLDC_1_1_MAX
)
445 actualVersion
= SJME_CLASS_CLDC_1_1
;
446 else if (fullVersion
>= SJME_CLASS_CLDC_1_8
&&
447 fullVersion
<= SJME_CLASS_CLDC_1_8_MAX
)
448 actualVersion
= SJME_CLASS_CLDC_1_8
;
453 error
= SJME_ERROR_INVALID_CLASS_VERSION
;
454 goto fail_badVersion
;
458 result
->version
= actualVersion
;
460 /* Parse the constant pool. */
462 if (sjme_error_is(error
= sjme_class_parseConstantPool(
463 inPool
, inStream
, inStringPool
, &pool
)) || pool
== NULL
)
466 /* We are using this, so count it up. */
467 if (sjme_error_is(error
= sjme_alloc_weakRef(pool
, NULL
)))
472 if (sjme_error_is(error
= sjme_class_classFlagsParse(
473 inStream
, &result
->flags
)))
476 /* Read in this name. */
478 if (sjme_error_is(error
= sjme_class_readPoolRefIndex(
479 inStream
, result
->pool
,
480 SJME_CLASS_POOL_TYPE_CLASS
,
481 SJME_JNI_FALSE
, &thisName
)) || thisName
== NULL
)
482 goto fail_readThisName
;
485 result
->name
= thisName
->classRef
.descriptor
;
486 if (sjme_error_is(error
= sjme_alloc_weakRef(
487 result
->name
, NULL
)))
488 goto fail_refThisName
;
490 /* Read in super name. */
492 if (sjme_error_is(error
= sjme_class_readPoolRefIndex(
493 inStream
, result
->pool
,
494 SJME_CLASS_POOL_TYPE_CLASS
,
495 SJME_JNI_TRUE
, &superName
)))
496 goto fail_readSuperName
;
498 /* Reference it, if valid. */
499 if (superName
!= NULL
)
501 result
->superName
= superName
->classRef
.descriptor
;
502 if (sjme_error_is(error
= sjme_alloc_weakRef(
503 result
->superName
, NULL
)))
504 goto fail_refSuperName
;
507 /* How many interfaces are there? */
509 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
510 inStream
, &interfaceCount
)) || interfaceCount
< 0)
511 goto fail_readInterfaceCount
;
513 /* Allocate interfaces count. */
514 interfaceNames
= NULL
;
515 if (sjme_error_is(error
= sjme_list_alloc(inPool
,
516 interfaceCount
, &interfaceNames
, sjme_stringPool_string
, 0)) ||
517 interfaceNames
== NULL
)
518 goto fail_allocInterfaceNames
;
519 result
->interfaceNames
= interfaceNames
;
521 /* Read in all interfaces. */
522 for (i
= 0; i
< interfaceCount
; i
++)
525 interfaceName
= NULL
;
526 if (sjme_error_is(error
= sjme_class_readPoolRefIndex(
527 inStream
, result
->pool
,
528 SJME_CLASS_POOL_TYPE_CLASS
,
529 SJME_JNI_FALSE
, &interfaceName
)) ||
530 interfaceName
== NULL
)
531 goto fail_readThisName
;
534 interfaceNames
->elements
[i
] = interfaceName
->classRef
.descriptor
;
535 if (sjme_error_is(error
= sjme_alloc_weakRef(
536 interfaceNames
->elements
[i
], NULL
)))
537 goto fail_refThisName
;
540 /* Read in field count. */
542 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
543 inStream
, &fieldCount
)) || fieldCount
< 0)
544 goto fail_readFieldCount
;
546 /* Setup list to store fields in. */
548 if (sjme_error_is(error
= sjme_list_alloc(inPool
,
549 fieldCount
, &fields
, sjme_class_fieldInfo
, 0)) || fields
== NULL
)
550 goto fail_allocFields
;
551 result
->fields
= fields
;
553 /* Load in and process each field. */
554 for (i
= 0; i
< fieldCount
; i
++)
556 /* Parse each field. */
557 if (sjme_error_is(error
= sjme_class_parseField(
558 inPool
, inStream
, result
->pool
, inStringPool
,
559 &fields
->elements
[i
])) ||
560 fields
->elements
[i
] == NULL
)
561 goto fail_parseField
;
564 /* Read in method count. */
566 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
567 inStream
, &methodCount
)) || methodCount
< 0)
568 goto fail_readMethodCount
;
570 /* Setup list to store methods in. */
572 if (sjme_error_is(error
= sjme_list_alloc(inPool
,
573 methodCount
, &methods
, sjme_class_methodInfo
, 0)) || methods
== NULL
)
574 goto fail_allocMethods
;
575 result
->methods
= methods
;
577 /* Load in and process each method. */
578 for (i
= 0; i
< methodCount
; i
++)
580 /* Parse each method. */
581 if (sjme_error_is(error
= sjme_class_parseMethod(
582 inPool
, inStream
, result
->pool
, inStringPool
,
583 &methods
->elements
[i
])) ||
584 methods
->elements
[i
] == NULL
)
585 goto fail_parseMethod
;
588 /* Parse attributes. */
589 if (sjme_error_is(error
= sjme_class_parseAttributes(
590 inPool
, inStream
, result
->pool
, inStringPool
,
591 sjme_class_classAttr
, result
)))
592 goto fail_parseAttributes
;
596 return SJME_ERROR_NONE
;
598 fail_parseAttributes
:
603 sjme_alloc_free(methods
);
605 result
->methods
= NULL
;
607 fail_readMethodCount
:
612 sjme_alloc_free(fields
);
614 result
->fields
= NULL
;
617 fail_allocInterfaceNames
:
618 if (interfaceNames
!= NULL
)
620 sjme_alloc_free(interfaceNames
);
621 interfaceNames
= NULL
;
622 result
->interfaceNames
= NULL
;
624 fail_readInterfaceCount
:
634 sjme_closeable_close(SJME_AS_CLOSEABLE(pool
));
646 sjme_closeable_close(SJME_AS_CLOSEABLE(result
));
647 return sjme_error_default(error
);
650 sjme_errorCode
sjme_class_parseAttributes(
651 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
652 sjme_attrInNotNull sjme_stream_input inStream
,
653 sjme_attrInNotNull sjme_class_poolInfo inConstPool
,
654 sjme_attrInNotNull sjme_stringPool inStringPool
,
655 sjme_attrInNotNull
const sjme_class_parseAttributeHandlerInfo
* handlers
,
656 sjme_attrInNotNull sjme_pointer context
)
658 sjme_errorCode error
;
661 sjme_class_poolEntry
* name
;
663 if (inPool
== NULL
|| inStream
== NULL
|| inConstPool
== NULL
||
664 inStringPool
== NULL
|| handlers
== NULL
|| context
== NULL
)
665 return SJME_ERROR_NULL_ARGUMENTS
;
669 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
670 inStream
, &count
)) || count
< 0)
673 /* Read individual attributes. */
674 for (i
= 0; i
< count
; i
++)
678 if (sjme_error_is(error
= sjme_class_readPoolRefIndex(
679 inStream
, inConstPool
,
680 SJME_CLASS_POOL_TYPE_UTF
,
681 SJME_JNI_FALSE
, &name
)) || name
== NULL
)
684 /* Read in length. */
686 if (sjme_error_is(error
= sjme_stream_inputReadValueJI(
687 inStream
, &len
)) || len
< 0)
690 /* Stage it for stack allocations. */
691 if (sjme_error_is(error
= sjme_class_parseAttribute(
692 inPool
, inStream
, inConstPool
, inStringPool
, handlers
,
693 context
, (sjme_lpcstr
)&name
->utf
.utf
->chars
[0],
695 goto fail_parseSingle
;
699 return SJME_ERROR_NONE
;
705 return sjme_error_default(error
);
708 sjme_errorCode
sjme_class_parseConstantPool(
709 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
710 sjme_attrInNotNull sjme_stream_input inStream
,
711 sjme_attrInNotNull sjme_stringPool inStringPool
,
712 sjme_attrOutNotNull sjme_class_poolInfo
* outPool
)
714 sjme_errorCode error
;
718 sjme_list_sjme_class_poolEntry
* entries
;
719 sjme_class_poolEntry
* entry
;
720 sjme_class_poolEntry
* target
;
721 sjme_stringPool_string utf
;
722 sjme_class_poolInfo result
;
724 if (inPool
== NULL
|| inStream
== NULL
|| outPool
== NULL
||
725 inStringPool
== NULL
)
726 return SJME_ERROR_NULL_ARGUMENTS
;
728 /* Make sure we can actually allocate this. */
730 if (sjme_error_is(error
= sjme_alloc_weakNew(inPool
,
731 sizeof(*result
), NULL
, NULL
,
732 (sjme_pointer
*)&result
, NULL
)) || result
== NULL
)
733 goto fail_allocResult
;
736 if (sjme_error_is(error
= sjme_nvm_initCommon(
737 SJME_AS_NVM_COMMON(result
), SJME_NVM_STRUCT_POOL
)))
738 goto fail_initCommon
;
740 /* Read in pool count. */
742 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
743 inStream
, &count
)) || count
< 0)
746 /* Invalid pool size? */
747 if (count
< 0 || count
>= INT16_MAX
)
749 error
= SJME_ERROR_INVALID_CLASS_POOL_COUNT
;
753 /* Count up by one, since zero is included! */
756 /* Allocate resultant entries, where they will all go. */
758 if (sjme_error_is(error
= sjme_list_alloc(inPool
,
759 count
, &entries
, sjme_class_poolEntry
, 0)) || entries
== NULL
)
762 /* Read in all entries. */
763 /* This is a first pass since index items can refer to later entries. */
764 for (index
= 1; index
< count
- 1; index
++)
766 /* Which entry is being written? */
767 entry
= &entries
->elements
[index
];
771 if (sjme_error_is(error
= sjme_stream_inputReadValueJB(
772 inStream
, &tag
)) || tag
< 0)
776 sjme_message("TAG: %d", tag
);
781 /* Which tag is this? */
784 /* Class reference. */
785 case SJME_CLASS_POOL_TYPE_CLASS
:
786 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
788 &entry
->classRef
.descriptorIndex
)))
793 case SJME_CLASS_POOL_TYPE_DOUBLE
:
794 if (sjme_error_is(error
= sjme_stream_inputReadValueJI(
796 (sjme_jint
*)&entry
->constDouble
.value
.hi
)))
798 if (sjme_error_is(error
= sjme_stream_inputReadValueJI(
800 (sjme_jint
*)&entry
->constDouble
.value
.lo
)))
804 /* Reference to a member. */
805 case SJME_CLASS_POOL_TYPE_FIELD
:
806 case SJME_CLASS_POOL_TYPE_INTERFACE_METHOD
:
807 case SJME_CLASS_POOL_TYPE_METHOD
:
808 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
810 &entry
->member
.inClassIndex
)))
812 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
814 &entry
->member
.nameAndTypeIndex
)))
818 /* Name and type information. */
819 case SJME_CLASS_POOL_TYPE_NAME_AND_TYPE
:
820 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
822 &entry
->nameAndType
.nameIndex
)))
824 if (sjme_error_is(error
= sjme_stream_inputReadValueJS(
826 &entry
->nameAndType
.descriptorIndex
)))
831 case SJME_CLASS_POOL_TYPE_UTF
:
833 if (sjme_error_is(error
= sjme_stringPool_locateStream(
834 inStringPool
, inStream
, &utf
)) || utf
== NULL
)
838 sjme_message("Read UTF: %s",
841 /* Store and count up entry as we are using it now. */
842 entry
->utf
.utf
= utf
;
843 if (sjme_error_is(error
= sjme_alloc_weakRef(
849 sjme_todo("Impl? %d", tag
);
850 return SJME_ERROR_NOT_IMPLEMENTED
;
854 /* Second stage item linking. */
855 for (index
= 1; index
< count
- 1; index
++)
857 /* Which entry is being initialized? */
858 entry
= &entries
->elements
[index
];
860 /* Initialize accordingly. */
863 /* These are base elements that need no initialization. */
864 case SJME_CLASS_POOL_TYPE_UTF
:
865 case SJME_CLASS_POOL_TYPE_INTEGER
:
866 case SJME_CLASS_POOL_TYPE_FLOAT
:
867 case SJME_CLASS_POOL_TYPE_LONG
:
868 case SJME_CLASS_POOL_TYPE_DOUBLE
:
872 case SJME_CLASS_POOL_TYPE_CLASS
:
873 if (entry
->classRef
.descriptorIndex
<= 0 ||
874 entry
->classRef
.descriptorIndex
>= entries
->length
)
876 error
= SJME_ERROR_INVALID_CLASS_POOL_INDEX
;
880 /* Need to be a UTF string. */
881 target
= &entries
->elements
[entry
->classRef
.descriptorIndex
];
882 if (target
->type
!= SJME_CLASS_POOL_TYPE_UTF
)
884 error
= SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE
;
888 /* Refer to it and count up, since we are using it. */
889 entry
->classRef
.descriptor
= target
->utf
.utf
;
890 if (sjme_error_is(error
= sjme_alloc_weakRef(
891 entry
->classRef
.descriptor
, NULL
)))
895 /* Member reference. */
896 case SJME_CLASS_POOL_TYPE_FIELD
:
897 case SJME_CLASS_POOL_TYPE_INTERFACE_METHOD
:
898 case SJME_CLASS_POOL_TYPE_METHOD
:
899 if (entry
->member
.inClassIndex
<= 0 ||
900 entry
->member
.inClassIndex
>= entries
->length
||
901 entry
->member
.nameAndTypeIndex
<= 0 ||
902 entry
->member
.nameAndTypeIndex
>= entries
->length
)
904 error
= SJME_ERROR_INVALID_CLASS_POOL_INDEX
;
908 /* Needs to be a class. */
909 target
= &entries
->elements
[entry
->member
.inClassIndex
];
910 if (target
->type
!= SJME_CLASS_POOL_TYPE_CLASS
)
912 error
= SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE
;
917 entry
->member
.inClass
=
918 (const sjme_class_poolEntryClass
*)target
;
920 /* Needs to be a name and type. */
921 target
= &entries
->elements
[entry
->member
.nameAndTypeIndex
];
922 if (target
->type
!= SJME_CLASS_POOL_TYPE_NAME_AND_TYPE
)
924 error
= SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE
;
928 /* Set name and type. */
929 entry
->member
.nameAndType
=
930 (const sjme_class_poolEntryNameAndType
*)target
;
933 case SJME_CLASS_POOL_TYPE_NAME_AND_TYPE
:
934 if (entry
->nameAndType
.nameIndex
<= 0 ||
935 entry
->nameAndType
.nameIndex
>= entries
->length
||
936 entry
->nameAndType
.descriptorIndex
<= 0 ||
937 entry
->nameAndType
.descriptorIndex
>= entries
->length
)
939 error
= SJME_ERROR_INVALID_CLASS_POOL_INDEX
;
943 /* Needs to be UTF. */
944 target
= &entries
->elements
[entry
->nameAndType
.nameIndex
];
945 if (target
->type
!= SJME_CLASS_POOL_TYPE_UTF
)
947 error
= SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE
;
952 entry
->nameAndType
.name
= target
->utf
.utf
;
953 if (sjme_error_is(error
= sjme_alloc_weakRef(
954 entry
->nameAndType
.name
, NULL
)))
957 /* Needs to be UTF. */
958 target
= &entries
->elements
[
959 entry
->nameAndType
.descriptorIndex
];
960 if (target
->type
!= SJME_CLASS_POOL_TYPE_UTF
)
962 error
= SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE
;
966 /* Set descriptor. */
967 entry
->nameAndType
.descriptor
= target
->utf
.utf
;
968 if (sjme_error_is(error
= sjme_alloc_weakRef(
969 entry
->nameAndType
.descriptor
, NULL
)))
974 sjme_todo("Impl? %d", tag
);
975 return SJME_ERROR_NOT_IMPLEMENTED
;
980 result
->pool
= entries
;
984 return SJME_ERROR_NONE
;
991 sjme_alloc_free(entries
);
997 sjme_closeable_close(SJME_AS_CLOSEABLE(result
));
998 return sjme_error_default(error
);
1001 sjme_errorCode
sjme_class_parseField(
1002 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
1003 sjme_attrInNotNull sjme_stream_input inStream
,
1004 sjme_attrInNotNull sjme_class_poolInfo inConstPool
,
1005 sjme_attrInNotNull sjme_stringPool inStringPool
,
1006 sjme_attrOutNotNull sjme_class_fieldInfo
* outField
)
1008 if (inPool
== NULL
|| inStream
== NULL
|| inConstPool
== NULL
||
1009 outField
== NULL
|| inStringPool
== NULL
)
1010 return SJME_ERROR_NULL_ARGUMENTS
;
1013 return SJME_ERROR_NOT_IMPLEMENTED
;
1016 sjme_errorCode
sjme_class_parseMethod(
1017 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
1018 sjme_attrInNotNull sjme_stream_input inStream
,
1019 sjme_attrInNotNull sjme_class_poolInfo inConstPool
,
1020 sjme_attrInNotNull sjme_stringPool inStringPool
,
1021 sjme_attrInOutNotNull sjme_class_methodInfo
* outMethod
)
1023 sjme_errorCode error
;
1024 sjme_class_methodInfo result
;
1025 sjme_class_poolEntry
* name
;
1026 sjme_class_poolEntry
* type
;
1028 if (inPool
== NULL
|| inStream
== NULL
|| inConstPool
== NULL
||
1029 outMethod
== NULL
|| inStringPool
== NULL
)
1030 return SJME_ERROR_NULL_ARGUMENTS
;
1032 /* Ensure we can allocate the result first. */
1034 if (sjme_error_is(error
= sjme_alloc_weakNew(inPool
,
1035 sizeof(*result
), NULL
, NULL
,
1036 (sjme_pointer
*)&result
, NULL
)) || result
== NULL
)
1037 goto fail_allocResult
;
1039 /* Initialize it. */
1040 if (sjme_error_is(error
= sjme_nvm_initCommon(
1041 SJME_AS_NVM_COMMON(result
),
1042 SJME_NVM_STRUCT_METHOD_INFO
)))
1043 goto fail_initResult
;
1045 /* Read in flags. */
1046 if (sjme_error_is(error
= sjme_class_methodFlagsParse(
1047 inStream
, &result
->flags
)))
1048 goto fail_readFlags
;
1052 if (sjme_error_is(error
= sjme_class_readPoolRefIndex(
1053 inStream
, inConstPool
,
1054 SJME_CLASS_POOL_TYPE_UTF
,
1055 SJME_JNI_FALSE
, &name
)) || name
== NULL
)
1059 result
->name
= name
->utf
.utf
;
1060 if (sjme_error_is(error
= sjme_alloc_weakRef(
1061 result
->name
, NULL
)))
1066 if (sjme_error_is(error
= sjme_class_readPoolRefIndex(
1067 inStream
, inConstPool
,
1068 SJME_CLASS_POOL_TYPE_UTF
,
1069 SJME_JNI_FALSE
, &type
)) || name
== NULL
)
1073 result
->type
= name
->utf
.utf
;
1074 if (sjme_error_is(error
= sjme_alloc_weakRef(
1075 result
->type
, NULL
)))
1078 /* Parse attributes. */
1079 if (sjme_error_is(error
= sjme_class_parseAttributes(
1080 inPool
, inStream
, inConstPool
, inStringPool
,
1081 sjme_class_methodAttr
, result
)))
1082 goto fail_parseAttributes
;
1085 *outMethod
= result
;
1086 return SJME_ERROR_NONE
;
1088 fail_parseAttributes
:
1097 sjme_closeable_close(SJME_AS_CLOSEABLE(result
));
1098 return sjme_error_default(error
);