Handling of more constant pool types.
[SquirrelJME.git] / nanocoat / src / classy.c
blobb8fd03640ffea1fc97dc0ecddd7dc3e4c37b5a38
1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
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 // -------------------------------------------------------------------------*/
10 #include <string.h>
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)
28 /** Public. */
29 #define SJME_CLASS_ACC_PUBLIC INT16_C(0x0001)
31 /** Private. */
32 #define SJME_CLASS_ACC_PRIVATE INT16_C(0x0002)
34 /** Protected. */
35 #define SJME_CLASS_ACC_PROTECTED INT16_C(0x0004)
37 /** Static member. */
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)
49 /** Bridge method. */
50 #define SJME_CLASS_ACC_BRIDGE INT16_C(0x0040)
52 /** Variable arguments. */
53 #define SJME_CLASS_ACC_VARARGS INT16_C(0x0080)
55 /** Native method. */
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)
83 sjme_errorCode error;
84 sjme_jshort index;
85 sjme_class_poolEntry* result;
87 if (inStream == NULL || inClassPool == NULL || outEntry == NULL)
88 return SJME_ERROR_NULL_ARGUMENTS;
90 /* Read in index. */
91 index = -1;
92 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
93 inStream, &index)))
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;
105 /* Success! */
106 *outEntry = result;
107 return SJME_ERROR_NONE;
110 static const sjme_class_parseAttributeHandlerInfo sjme_class_classAttr[] =
112 {NULL, NULL},
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;
125 /* Read in flags. */
126 rawFlags = -1;
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;
158 /* Success! */
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;
175 sjme_todo("Impl?");
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;
192 sjme_todo("Impl?");
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;
209 sjme_todo("Impl?");
210 return SJME_ERROR_NOT_IMPLEMENTED;
213 static const sjme_class_parseAttributeHandlerInfo sjme_class_codeAttr[] =
215 {"LineNumberTable",
216 sjme_class_codeAttrLineNumberTable},
217 {"StackMap",
218 sjme_class_codeAttrStackMap},
219 {"StackMapTable",
220 sjme_class_codeAttrStackMapTable},
221 {NULL, NULL},
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;
237 sjme_todo("Impl?");
238 return SJME_ERROR_NOT_IMPLEMENTED;
241 static const sjme_class_parseAttributeHandlerInfo sjme_class_fieldAttr[] =
243 {"ConstantValue", sjme_class_fieldAttrConstantValue},
244 {NULL, NULL},
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;
260 sjme_todo("Impl?");
261 return SJME_ERROR_NOT_IMPLEMENTED;
264 static const sjme_class_parseAttributeHandlerInfo sjme_class_methodAttr[] =
266 {"Code", sjme_class_methodAttrCode},
267 {NULL, NULL},
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;
280 /* Read in flags. */
281 rawFlags = -1;
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;
323 /* Success! */
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;
339 sjme_jint readCount;
340 sjme_class_parseAttributeHandlerInfo* at;
342 if (inPool == NULL || inStream == NULL || inConstPool == NULL ||
343 inStringPool == NULL || handlers == NULL || context == NULL ||
344 attrName == NULL)
345 return SJME_ERROR_NULL_ARGUMENTS;
347 if (attrLen < 0)
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. */
357 readCount = -1;
358 if (sjme_error_is(error = sjme_stream_inputReadFully(
359 inStream, &readCount, attrData, attrLen)) ||
360 readCount < 0)
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)
370 /* Debug. */
371 sjme_message("No handler for attribute %s.", attrName);
372 #endif
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 ||
398 outClass == NULL)
399 return SJME_ERROR_NONE;
401 /* Make sure we can actually allocate the resultant class. */
402 result = NULL;
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;
408 /* Initialize. */
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. */
415 magic = INT32_MAX;
416 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
417 inStream, &magic)))
418 goto fail_readMagic;
420 /* It must be valid! */
421 if (magic != SJME_CLASS_MAGIC)
423 error = SJME_ERROR_INVALID_CLASS_MAGIC;
424 goto fail_badMagic;
427 /* Read in version info. */
428 minor = INT16_MAX;
429 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
430 inStream, &minor)))
431 goto fail_readMinor;
433 major = INT16_MAX;
434 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
435 inStream, &major)))
436 goto fail_readMajor;
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;
450 /* Not valid. */
451 else
453 error = SJME_ERROR_INVALID_CLASS_VERSION;
454 goto fail_badVersion;
457 /* Set version. */
458 result->version = actualVersion;
460 /* Parse the constant pool. */
461 pool = NULL;
462 if (sjme_error_is(error = sjme_class_parseConstantPool(
463 inPool, inStream, inStringPool, &pool)) || pool == NULL)
464 goto fail_parsePool;
466 /* We are using this, so count it up. */
467 if (sjme_error_is(error = sjme_alloc_weakRef(pool, NULL)))
468 goto fail_countPool;
469 result->pool = pool;
471 /* Read in flags. */
472 if (sjme_error_is(error = sjme_class_classFlagsParse(
473 inStream, &result->flags)))
474 goto fail_readFlags;
476 /* Read in this name. */
477 thisName = NULL;
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;
484 /* Reference it. */
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. */
491 superName = NULL;
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? */
508 interfaceCount = -1;
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++)
524 /* Read in name. */
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;
533 /* Reference it. */
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. */
541 fieldCount = -1;
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. */
547 fields = NULL;
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. */
565 methodCount = -1;
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. */
571 methods = NULL;
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;
594 /* Success! */
595 *outClass = result;
596 return SJME_ERROR_NONE;
598 fail_parseAttributes:
599 fail_parseMethod:
600 fail_allocMethods:
601 if (methods != NULL)
603 sjme_alloc_free(methods);
604 methods = NULL;
605 result->methods = NULL;
607 fail_readMethodCount:
608 fail_parseField:
609 fail_allocFields:
610 if (fields != NULL)
612 sjme_alloc_free(fields);
613 fields = NULL;
614 result->fields = NULL;
616 fail_readFieldCount:
617 fail_allocInterfaceNames:
618 if (interfaceNames != NULL)
620 sjme_alloc_free(interfaceNames);
621 interfaceNames = NULL;
622 result->interfaceNames = NULL;
624 fail_readInterfaceCount:
625 fail_refSuperName:
626 fail_readSuperName:
627 fail_refThisName:
628 fail_readThisName:
629 fail_readFlags:
630 fail_countPool:
631 fail_parsePool:
632 if (pool != NULL)
634 sjme_closeable_close(SJME_AS_CLOSEABLE(pool));
635 pool = NULL;
636 result->pool = NULL;
638 fail_badVersion:
639 fail_readMinor:
640 fail_readMajor:
641 fail_badMagic:
642 fail_readMagic:
643 fail_initResult:
644 fail_allocResult:
645 if (result != NULL)
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;
659 sjme_jshort count;
660 sjme_jint i, len;
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;
667 /* Read in count. */
668 count = -1;
669 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
670 inStream, &count)) || count < 0)
671 goto fail_readCount;
673 /* Read individual attributes. */
674 for (i = 0; i < count; i++)
676 /* Read in name. */
677 name = NULL;
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)
682 goto fail_readName;
684 /* Read in length. */
685 len = -1;
686 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
687 inStream, &len)) || len < 0)
688 goto fail_readLen;
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],
694 len)))
695 goto fail_parseSingle;
698 /* Success! */
699 return SJME_ERROR_NONE;
701 fail_parseSingle:
702 fail_readLen:
703 fail_readName:
704 fail_readCount:
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;
715 sjme_jshort count;
716 sjme_jint index;
717 sjme_jbyte tag;
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. */
729 result = NULL;
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;
735 /* Initialize it. */
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. */
741 count = -1;
742 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
743 inStream, &count)) || count < 0)
744 goto fail_readCount;
746 /* Invalid pool size? */
747 if (count < 0 || count >= INT16_MAX)
749 error = SJME_ERROR_INVALID_CLASS_POOL_COUNT;
750 goto fail_poolCount;
753 /* Count up by one, since zero is included! */
754 count += 1;
756 /* Allocate resultant entries, where they will all go. */
757 entries = NULL;
758 if (sjme_error_is(error = sjme_list_alloc(inPool,
759 count, &entries, sjme_class_poolEntry, 0)) || entries == NULL)
760 goto fail_entryList;
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];
769 /* Read in tag. */
770 tag = -1;
771 if (sjme_error_is(error = sjme_stream_inputReadValueJB(
772 inStream, &tag)) || tag < 0)
773 goto fail_readTag;
775 /* Debug. */
776 sjme_message("TAG: %d", tag);
778 /* Set tag. */
779 entry->type = tag;
781 /* Which tag is this? */
782 switch (tag)
784 /* Class reference. */
785 case SJME_CLASS_POOL_TYPE_CLASS:
786 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
787 inStream,
788 &entry->classRef.descriptorIndex)))
789 goto fail_readItem;
790 break;
792 /* Double value. */
793 case SJME_CLASS_POOL_TYPE_DOUBLE:
794 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
795 inStream,
796 (sjme_jint*)&entry->constDouble.value.hi)))
797 goto fail_readItem;
798 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
799 inStream,
800 (sjme_jint*)&entry->constDouble.value.lo)))
801 goto fail_readItem;
802 break;
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(
809 inStream,
810 &entry->member.inClassIndex)))
811 goto fail_readItem;
812 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
813 inStream,
814 &entry->member.nameAndTypeIndex)))
815 goto fail_readItem;
816 break;
818 /* Name and type information. */
819 case SJME_CLASS_POOL_TYPE_NAME_AND_TYPE:
820 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
821 inStream,
822 &entry->nameAndType.nameIndex)))
823 goto fail_readItem;
824 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
825 inStream,
826 &entry->nameAndType.descriptorIndex)))
827 goto fail_readItem;
828 break;
830 /* UTF String. */
831 case SJME_CLASS_POOL_TYPE_UTF:
832 utf = NULL;
833 if (sjme_error_is(error = sjme_stringPool_locateStream(
834 inStringPool, inStream, &utf)) || utf == NULL)
835 goto fail_readItem;
837 /* Debug. */
838 sjme_message("Read UTF: %s",
839 utf->chars);
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(
844 utf, NULL)))
845 goto fail_readItem;
846 break;
848 default:
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. */
861 switch (entry->type)
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:
869 break;
871 /* Class type. */
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;
877 goto fail_initItem;
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;
885 goto fail_initItem;
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)))
892 goto fail_initItem;
893 break;
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;
905 goto fail_initItem;
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;
913 goto fail_initItem;
916 /* Set class. */
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;
925 goto fail_initItem;
928 /* Set name and type. */
929 entry->member.nameAndType =
930 (const sjme_class_poolEntryNameAndType*)target;
931 break;
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;
940 goto fail_initItem;
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;
948 goto fail_initItem;
951 /* Set name. */
952 entry->nameAndType.name = target->utf.utf;
953 if (sjme_error_is(error = sjme_alloc_weakRef(
954 entry->nameAndType.name, NULL)))
955 goto fail_initItem;
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;
963 goto fail_initItem;
966 /* Set descriptor. */
967 entry->nameAndType.descriptor = target->utf.utf;
968 if (sjme_error_is(error = sjme_alloc_weakRef(
969 entry->nameAndType.descriptor, NULL)))
970 goto fail_initItem;
971 break;
973 default:
974 sjme_todo("Impl? %d", tag);
975 return SJME_ERROR_NOT_IMPLEMENTED;
979 /* Setup details. */
980 result->pool = entries;
982 /* Success! */
983 *outPool = result;
984 return SJME_ERROR_NONE;
986 fail_initItem:
987 fail_readItem:
988 fail_readTag:
989 fail_entryList:
990 if (entries != NULL)
991 sjme_alloc_free(entries);
992 fail_poolCount:
993 fail_readCount:
994 fail_initCommon:
995 fail_allocResult:
996 if (result != NULL)
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;
1012 sjme_todo("Impl?");
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. */
1033 result = NULL;
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;
1050 /* Read in name. */
1051 name = NULL;
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)
1056 goto fail_readName;
1058 /* Reference it. */
1059 result->name = name->utf.utf;
1060 if (sjme_error_is(error = sjme_alloc_weakRef(
1061 result->name, NULL)))
1062 goto fail_refName;
1064 /* Read in type. */
1065 type = 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)
1070 goto fail_readType;
1072 /* Reference it. */
1073 result->type = name->utf.utf;
1074 if (sjme_error_is(error = sjme_alloc_weakRef(
1075 result->type, NULL)))
1076 goto fail_refType;
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;
1084 /* Success! */
1085 *outMethod = result;
1086 return SJME_ERROR_NONE;
1088 fail_parseAttributes:
1089 fail_refType:
1090 fail_readType:
1091 fail_refName:
1092 fail_readName:
1093 fail_readFlags:
1094 fail_initResult:
1095 fail_allocResult:
1096 if (result != NULL)
1097 sjme_closeable_close(SJME_AS_CLOSEABLE(result));
1098 return sjme_error_default(error);