Adjust sourcize.c to use _snprintf if using MSVC.
[SquirrelJME.git] / nanocoat / src / classy.c
blob67024f7c083b5abce8c450e5a87628b54e4e3505
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 /** Field is volatile. */
71 #define SJME_CLASS_ACC_VOLATILE INT16_C(0x0040)
73 /** Field is transient. */
74 #define SJME_CLASS_ACC_TRANSIENT INT16_C(0x0080)
76 /** Class is an annotation. */
77 #define SJME_CLASS_ACC_ANNOTATION INT16_C(0x2000)
79 /** Class is an enum. */
80 #define SJME_CLASS_ACC_ENUM INT16_C(0x4000)
82 static sjme_errorCode sjme_class_readPoolRefIndex(
83 sjme_attrInNotNull sjme_stream_input inStream,
84 sjme_attrInNotNull sjme_class_poolInfo inClassPool,
85 sjme_attrInPositiveNonZero sjme_class_poolType desireType,
86 sjme_attrInValue sjme_jboolean canNull,
87 sjme_attrOutNotNull sjme_class_poolEntry** outEntry)
89 sjme_errorCode error;
90 sjme_jshort index;
91 sjme_class_poolEntry* result;
93 if (inStream == NULL || inClassPool == NULL || outEntry == NULL)
94 return SJME_ERROR_NULL_ARGUMENTS;
96 /* Read in index. */
97 index = -1;
98 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
99 inStream, &index)))
100 return sjme_error_default(error);
102 /* Not a valid index? */
103 if (index <= 0 || index >= inClassPool->pool->length)
105 /* Can be zero index for nothing, however. */
106 if (index == 0 && canNull)
108 *outEntry = NULL;
109 return SJME_ERROR_NONE;
112 return SJME_ERROR_INVALID_CLASS_POOL_INDEX;
115 /* Must be the desired type. */
116 result = &inClassPool->pool->elements[index];
117 if (result->type != desireType)
118 return SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE;
120 /* Success! */
121 *outEntry = result;
122 return SJME_ERROR_NONE;
125 static const sjme_class_parseAttributeHandlerInfo sjme_class_classAttr[] =
127 {NULL, NULL},
130 static sjme_errorCode sjme_class_classFlagsParse(
131 sjme_attrInNotNull sjme_stream_input inStream,
132 sjme_attrOutNotNull sjme_class_classFlags* outFlags)
134 sjme_errorCode error;
135 sjme_jshort rawFlags;
137 if (inStream == NULL || outFlags == NULL)
138 return SJME_ERROR_NULL_ARGUMENTS;
140 /* Read in flags. */
141 rawFlags = -1;
142 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
143 inStream, &rawFlags)) || rawFlags < 0)
144 return sjme_error_default(error);
146 /* Translate to bitfield. */
147 if ((rawFlags & SJME_CLASS_ACC_PUBLIC) != 0)
148 outFlags->access.public = SJME_JNI_TRUE;
149 if ((rawFlags & SJME_CLASS_ACC_FINAL) != 0)
150 outFlags->final = SJME_JNI_TRUE;
151 if ((rawFlags & SJME_CLASS_ACC_SUPER) != 0)
152 outFlags->super = SJME_JNI_TRUE;
153 if ((rawFlags & SJME_CLASS_ACC_INTERFACE) != 0)
154 outFlags->interface = SJME_JNI_TRUE;
155 if ((rawFlags & SJME_CLASS_ACC_ABSTRACT) != 0)
156 outFlags->abstract = SJME_JNI_TRUE;
157 if ((rawFlags & SJME_CLASS_ACC_SYNTHETIC) != 0)
158 outFlags->synthetic = SJME_JNI_TRUE;
159 if ((rawFlags & SJME_CLASS_ACC_ANNOTATION) != 0)
160 outFlags->annotation = SJME_JNI_TRUE;
161 if ((rawFlags & SJME_CLASS_ACC_ENUM) != 0)
162 outFlags->enumeration = SJME_JNI_TRUE;
164 /* Cannot be abstract and final. */
165 /* Annotation must be an interface. */
166 /* Interface must be abstract and not final, super, or enum */
167 if ((outFlags->abstract && outFlags->final) ||
168 (outFlags->annotation && !outFlags->interface) ||
169 (outFlags->interface && (!outFlags->abstract ||
170 outFlags->final || outFlags->super || outFlags->enumeration)))
171 return SJME_ERROR_INVALID_CLASS_FLAGS;
173 /* Success! */
174 return SJME_ERROR_NONE;
177 static sjme_errorCode sjme_class_codeAttrLineNumberTable(
178 sjme_attrInNotNull sjme_alloc_pool* inPool,
179 sjme_attrInNotNull sjme_class_poolInfo inConstPool,
180 sjme_attrInNotNull sjme_stringPool inStringPool,
181 sjme_attrInNotNull sjme_pointer context,
182 sjme_attrInNotNull sjme_lpcstr attrName,
183 sjme_attrInNotNull sjme_stream_input attrStream,
184 sjme_attrInNotNullBuf(attrLen) sjme_pointer attrData,
185 sjme_attrInPositive sjme_jint attrLen)
187 if (inPool == NULL || inConstPool == NULL || inStringPool == NULL ||
188 context == NULL || attrName == NULL || attrData == NULL ||
189 attrStream == NULL)
190 return SJME_ERROR_NULL_ARGUMENTS;
192 sjme_todo("Impl?");
193 return SJME_ERROR_NOT_IMPLEMENTED;
196 static sjme_errorCode sjme_class_codeAttrStackMap(
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_attrInNotNull sjme_stream_input attrStream,
203 sjme_attrInNotNullBuf(attrLen) sjme_pointer attrData,
204 sjme_attrInPositive sjme_jint attrLen)
206 if (inPool == NULL || inConstPool == NULL || inStringPool == NULL ||
207 context == NULL || attrName == NULL || attrData == NULL ||
208 attrStream == NULL)
209 return SJME_ERROR_NULL_ARGUMENTS;
211 sjme_todo("Impl?");
212 return SJME_ERROR_NOT_IMPLEMENTED;
215 static sjme_errorCode sjme_class_codeAttrStackMapTable(
216 sjme_attrInNotNull sjme_alloc_pool* inPool,
217 sjme_attrInNotNull sjme_class_poolInfo inConstPool,
218 sjme_attrInNotNull sjme_stringPool inStringPool,
219 sjme_attrInNotNull sjme_pointer context,
220 sjme_attrInNotNull sjme_lpcstr attrName,
221 sjme_attrInNotNull sjme_stream_input attrStream,
222 sjme_attrInNotNullBuf(attrLen) sjme_pointer attrData,
223 sjme_attrInPositive sjme_jint attrLen)
225 if (inPool == NULL || inConstPool == NULL || inStringPool == NULL ||
226 context == NULL || attrName == NULL || attrData == NULL ||
227 attrStream == NULL)
228 return SJME_ERROR_NULL_ARGUMENTS;
230 sjme_todo("Impl?");
231 return SJME_ERROR_NOT_IMPLEMENTED;
234 static const sjme_class_parseAttributeHandlerInfo sjme_class_codeAttr[] =
236 #if 0
237 {"LineNumberTable",
238 sjme_class_codeAttrLineNumberTable},
239 {"StackMap",
240 sjme_class_codeAttrStackMap},
241 {"StackMapTable",
242 sjme_class_codeAttrStackMapTable},
243 #endif
244 {NULL, NULL},
247 static sjme_errorCode sjme_class_fieldAttrConstantValue(
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_attrInNotNull sjme_stream_input attrStream,
254 sjme_attrInNotNullBuf(attrLen) sjme_pointer attrData,
255 sjme_attrInPositive sjme_jint attrLen)
257 sjme_errorCode error;
258 sjme_class_fieldInfo fieldInfo;
259 sjme_jshort index;
260 sjme_class_poolEntry* item;
262 fieldInfo = context;
263 if (inPool == NULL || inConstPool == NULL || inStringPool == NULL ||
264 context == NULL || attrName == NULL || attrData == NULL ||
265 attrStream == NULL || fieldInfo == NULL)
266 return SJME_ERROR_NULL_ARGUMENTS;
268 /* Read the constant value index. */
269 index = -1;
270 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
271 attrStream, &index)) || index < 0)
272 return sjme_error_default(error);
274 /* Make sure it is valid. */
275 if (index <= 0 || index >= inConstPool->pool->length)
276 return SJME_ERROR_INVALID_CLASS_POOL_INDEX;
278 /* Process based on the pool type used. */
279 item = &inConstPool->pool->elements[index];
280 if (item->type == SJME_CLASS_POOL_TYPE_INTEGER)
282 fieldInfo->constVal.type = SJME_JAVA_TYPE_ID_INTEGER;
283 fieldInfo->constVal.value.java.i = item->constInteger.value;
285 else if (item->type == SJME_CLASS_POOL_TYPE_FLOAT)
287 fieldInfo->constVal.type = SJME_JAVA_TYPE_ID_FLOAT;
288 fieldInfo->constVal.value.java.f = item->constFloat.value;
290 else if (item->type == SJME_CLASS_POOL_TYPE_LONG)
292 fieldInfo->constVal.type = SJME_JAVA_TYPE_ID_LONG;
293 fieldInfo->constVal.value.java.j = item->constLong.value;
295 else if (item->type == SJME_CLASS_POOL_TYPE_DOUBLE)
297 fieldInfo->constVal.type = SJME_JAVA_TYPE_ID_DOUBLE;
298 fieldInfo->constVal.value.java.d = item->constDouble.value;
300 else if (item->type == SJME_CLASS_POOL_TYPE_STRING)
302 fieldInfo->constVal.type = SJME_JAVA_TYPE_ID_OBJECT;
303 fieldInfo->constVal.value.string = item->constString.value;
305 /* Count up as we are using it. */
306 if (sjme_error_is(error = sjme_alloc_weakRef(
307 fieldInfo->constVal.value.string, NULL)))
308 return sjme_error_default(error);
311 /* Invalid! */
312 else
313 return SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE;
315 /* Success! */
316 return SJME_ERROR_NONE;
319 static const sjme_class_parseAttributeHandlerInfo sjme_class_fieldAttr[] =
321 {"ConstantValue", sjme_class_fieldAttrConstantValue},
322 {NULL, NULL},
325 static sjme_errorCode sjme_class_fieldFlagsParse(
326 sjme_attrInNotNull sjme_stream_input inStream,
327 sjme_attrOutNotNull sjme_class_fieldFlags* outFlags)
329 sjme_errorCode error;
330 sjme_jshort rawFlags;
332 if (inStream == NULL || outFlags == NULL)
333 return SJME_ERROR_NULL_ARGUMENTS;
335 /* Read in flags. */
336 rawFlags = -1;
337 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
338 inStream, &rawFlags)) || rawFlags < 0)
339 return sjme_error_default(error);
341 /* Translate to bitfield. */
342 memset(outFlags, 0, sizeof(*outFlags));
343 if ((rawFlags & SJME_CLASS_ACC_PUBLIC) != 0)
344 outFlags->member.access.public = SJME_JNI_TRUE;
345 if ((rawFlags & SJME_CLASS_ACC_PRIVATE) != 0)
346 outFlags->member.access.private = SJME_JNI_TRUE;
347 if ((rawFlags & SJME_CLASS_ACC_PROTECTED) != 0)
348 outFlags->member.access.protected = SJME_JNI_TRUE;
349 if ((rawFlags & SJME_CLASS_ACC_STATIC) != 0)
350 outFlags->member.isStatic = SJME_JNI_TRUE;
351 if ((rawFlags & SJME_CLASS_ACC_FINAL) != 0)
352 outFlags->member.final = SJME_JNI_TRUE;
353 if ((rawFlags & SJME_CLASS_ACC_VOLATILE) != 0)
354 outFlags->isVolatile = SJME_JNI_TRUE;
355 if ((rawFlags & SJME_CLASS_ACC_TRANSIENT) != 0)
356 outFlags->transient = SJME_JNI_TRUE;
357 if ((rawFlags & SJME_CLASS_ACC_ENUM) != 0)
358 outFlags->enumeration = SJME_JNI_TRUE;
359 if ((rawFlags & SJME_CLASS_ACC_SYNTHETIC) != 0)
360 outFlags->member.synthetic = SJME_JNI_TRUE;
362 /* Can only have a single access mode. */
363 /* Cannot be both final and volatile. */
364 if (((outFlags->member.access.public +
365 outFlags->member.access.protected +
366 outFlags->member.access.private) > 1) ||
367 (outFlags->member.final && outFlags->isVolatile))
368 return SJME_ERROR_INVALID_FIELD_FLAGS;
370 /* Success! */
371 return SJME_ERROR_NONE;
374 static sjme_errorCode sjme_class_methodAttrCode(
375 sjme_attrInNotNull sjme_alloc_pool* inPool,
376 sjme_attrInNotNull sjme_class_poolInfo inConstPool,
377 sjme_attrInNotNull sjme_stringPool inStringPool,
378 sjme_attrInNotNull sjme_pointer context,
379 sjme_attrInNotNull sjme_lpcstr attrName,
380 sjme_attrInNotNull sjme_stream_input attrStream,
381 sjme_attrInNotNullBuf(attrLen) sjme_pointer attrData,
382 sjme_attrInPositive sjme_jint attrLen)
384 sjme_errorCode error;
385 sjme_jshort maxStack, maxLocals, numExcept;
386 sjme_jint codeLen, i, actualCodeLen;
387 sjme_class_methodInfo methodInfo;
388 sjme_class_codeInfo result;
389 sjme_jubyte* rawCode;
390 sjme_list_sjme_class_exceptionHandler* excepts;
391 sjme_class_exceptionHandler* except;
393 methodInfo = context;
394 if (inPool == NULL || inConstPool == NULL || inStringPool == NULL ||
395 context == NULL || attrName == NULL || attrData == NULL ||
396 attrStream == NULL || methodInfo == NULL)
397 return SJME_ERROR_NULL_ARGUMENTS;
399 /* Can only have one. */
400 if (methodInfo->code != NULL)
401 return SJME_ERROR_METHOD_MULTIPLE_CODE;
403 /* Make sure we can allocate this. */
404 result = NULL;
405 if (sjme_error_is(error = sjme_nvm_alloc(inPool,
406 sizeof(*result), SJME_NVM_STRUCT_CODE,
407 SJME_AS_NVM_COMMONP(&result))) || result == NULL)
408 goto fail_allocResult;
410 /* In this method! */
411 result->inMethod = methodInfo;
413 /* Read in max stack and locals. */
414 maxStack = -1;
415 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
416 attrStream, &maxStack)) || maxStack < 0)
417 goto fail_readMaxStack;
418 maxLocals = -1;
419 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
420 attrStream, &maxLocals)) || maxLocals < 0)
421 goto fail_readMaxLocals;
423 /* Set. */
424 result->maxStack = maxStack;
425 result->maxLocals = maxLocals;
427 /* Read in code length. */
428 codeLen = -1;
429 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
430 attrStream, &codeLen)) || codeLen <= 0)
431 goto fail_readCodeLen;
433 /* Allocate. */
434 rawCode = sjme_alloca(codeLen);
435 if (rawCode == NULL)
437 error = SJME_ERROR_OUT_OF_MEMORY;
438 goto fail_allocRawCode;
440 memset(rawCode, 0, codeLen);
442 /* Read in code. */
443 if (sjme_error_is(error = sjme_stream_inputReadFully(
444 attrStream, &actualCodeLen,
445 rawCode, codeLen)) ||
446 actualCodeLen != codeLen)
447 goto fail_readRawCode;
449 /* Read in exception table count. */
450 numExcept = -1;
451 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
452 attrStream, &numExcept)) || numExcept < 0)
453 goto fail_readNumExcept;
455 /* Only if there are actual exceptions. */
456 excepts = NULL;
457 if (numExcept > 0)
459 /* Allocate base table. */
460 if (sjme_error_is(error = sjme_list_alloc(inPool,
461 numExcept, &excepts, sjme_class_exceptionHandler, 0)) ||
462 excepts == NULL)
463 goto fail_allocExcepts;
464 result->exceptions = excepts;
466 /* Read in each exception. */
467 for (i = 0; i < numExcept; i++)
469 /* Which is being read into? */
470 except = &excepts->elements[i];
472 /* Read in values. */
473 except->range.start = -1;
474 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
475 attrStream, &except->range.start)) ||
476 except->range.start < 0)
477 goto fail_exceptShorts;
478 except->range.end = -1;
479 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
480 attrStream, &except->range.end)) ||
481 except->range.end < 0)
482 goto fail_exceptShorts;
483 except->handlerPc = -1;
484 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
485 attrStream, &except->handlerPc)) ||
486 except->handlerPc < 0)
487 goto fail_exceptShorts;
489 /* Read in handler class. */
490 except->handles = NULL;
491 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
492 attrStream, inConstPool,
493 SJME_CLASS_POOL_TYPE_CLASS,
494 SJME_JNI_TRUE,
495 (sjme_class_poolEntry**)&except->handles)))
496 goto fail_exceptHandles;
500 /* Parse attributes. */
501 if (sjme_error_is(error = sjme_class_parseAttributes(
502 inPool, attrStream, inConstPool, inStringPool,
503 sjme_class_codeAttr, result)))
504 goto fail_parseAttributes;
506 /* Make sure the code is referenced. */
507 methodInfo->code = result;
508 if (sjme_error_is(error = sjme_alloc_weakRef(result, NULL)))
509 goto fail_refCode;
511 /* Success! */
512 return SJME_ERROR_NONE;
513 fail_refCode:
514 fail_parseAttributes:
515 fail_exceptHandles:
516 fail_exceptShorts:
517 fail_allocExcepts:
518 fail_readNumExcept:
519 fail_readRawCode:
520 fail_allocRawCode:
521 fail_readCodeLen:
522 fail_readMaxLocals:
523 fail_readMaxStack:
524 fail_allocResult:
525 if (result != NULL)
526 sjme_closeable_close(SJME_AS_CLOSEABLE(result));
527 return sjme_error_default(error);
530 static const sjme_class_parseAttributeHandlerInfo sjme_class_methodAttr[] =
532 {"Code", sjme_class_methodAttrCode},
533 {NULL, NULL},
536 static sjme_errorCode sjme_class_methodFlagsParse(
537 sjme_attrInNotNull sjme_stream_input inStream,
538 sjme_attrOutNotNull sjme_class_methodFlags* outFlags)
540 sjme_errorCode error;
541 sjme_jshort rawFlags;
543 if (inStream == NULL || outFlags == NULL)
544 return SJME_ERROR_NULL_ARGUMENTS;
546 /* Read in flags. */
547 rawFlags = -1;
548 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
549 inStream, &rawFlags)) || rawFlags < 0)
550 return sjme_error_default(error);
552 /* Translate to bitfield. */
553 memset(outFlags, 0, sizeof(*outFlags));
554 if ((rawFlags & SJME_CLASS_ACC_PUBLIC) != 0)
555 outFlags->member.access.public = SJME_JNI_TRUE;
556 if ((rawFlags & SJME_CLASS_ACC_PRIVATE) != 0)
557 outFlags->member.access.private = SJME_JNI_TRUE;
558 if ((rawFlags & SJME_CLASS_ACC_PROTECTED) != 0)
559 outFlags->member.access.protected = SJME_JNI_TRUE;
560 if ((rawFlags & SJME_CLASS_ACC_STATIC) != 0)
561 outFlags->member.isStatic = SJME_JNI_TRUE;
562 if ((rawFlags & SJME_CLASS_ACC_FINAL) != 0)
563 outFlags->member.final = SJME_JNI_TRUE;
564 if ((rawFlags & SJME_CLASS_ACC_SYNCHRONIZED) != 0)
565 outFlags->synchronized = SJME_JNI_TRUE;
566 if ((rawFlags & SJME_CLASS_ACC_BRIDGE) != 0)
567 outFlags->bridge = SJME_JNI_TRUE;
568 if ((rawFlags & SJME_CLASS_ACC_VARARGS) != 0)
569 outFlags->varargs = SJME_JNI_TRUE;
570 if ((rawFlags & SJME_CLASS_ACC_NATIVE) != 0)
571 outFlags->native = SJME_JNI_TRUE;
572 if ((rawFlags & SJME_CLASS_ACC_ABSTRACT) != 0)
573 outFlags->abstract = SJME_JNI_TRUE;
574 if ((rawFlags & SJME_CLASS_ACC_STRICTFP) != 0)
575 outFlags->strictfp = SJME_JNI_TRUE;
576 if ((rawFlags & SJME_CLASS_ACC_SYNTHETIC) != 0)
577 outFlags->member.synthetic = SJME_JNI_TRUE;
579 /* Can only have a single access mode. */
580 /* Abstract cannot be final, private, static, strict, or synchronized. */
581 if (((outFlags->member.access.public +
582 outFlags->member.access.protected +
583 outFlags->member.access.private) > 1) ||
584 (outFlags->abstract && (outFlags->member.final ||
585 outFlags->native || outFlags->member.access.private ||
586 outFlags->member.isStatic || outFlags->strictfp ||
587 outFlags->synchronized)))
588 return SJME_ERROR_INVALID_METHOD_FLAGS;
590 /* Success! */
591 return SJME_ERROR_NONE;
594 static sjme_errorCode sjme_class_parseAttribute(
595 sjme_attrInNotNull sjme_alloc_pool* inPool,
596 sjme_attrInNotNull sjme_stream_input inStream,
597 sjme_attrInNotNull sjme_class_poolInfo inConstPool,
598 sjme_attrInNotNull sjme_stringPool inStringPool,
599 sjme_attrInNotNull const sjme_class_parseAttributeHandlerInfo* handlers,
600 sjme_attrInNotNull sjme_pointer context,
601 sjme_attrInNotNull sjme_lpcstr attrName,
602 sjme_attrInPositive sjme_jint attrLen)
604 sjme_errorCode error, errorC;
605 sjme_jubyte* attrData;
606 sjme_jint readCount;
607 const sjme_class_parseAttributeHandlerInfo* at;
608 sjme_stream_input attrStream;
610 if (inPool == NULL || inStream == NULL || inConstPool == NULL ||
611 inStringPool == NULL || handlers == NULL || context == NULL ||
612 attrName == NULL)
613 return SJME_ERROR_NULL_ARGUMENTS;
615 if (attrLen < 0)
616 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
618 /* Allocate buffer to read in the data. */
619 attrData = sjme_alloca(attrLen);
620 if (attrData == NULL)
621 return SJME_ERROR_OUT_OF_MEMORY;
622 memset(attrData, 0, attrLen);
624 /* Read in everything. */
625 readCount = -1;
626 if (sjme_error_is(error = sjme_stream_inputReadFully(
627 inStream, &readCount, attrData, attrLen)) ||
628 readCount < 0)
629 return sjme_error_default(error);
631 /* Find and call handler for this. */
632 for (at = handlers; at->name != NULL && at->handler != NULL; at++)
633 if (0 == strcmp(at->name, attrName))
635 /* Load stream over the data. */
636 attrStream = NULL;
637 if (sjme_error_is(error = sjme_stream_inputOpenMemory(
638 inPool, &attrStream,
639 attrData, attrLen)) || attrStream == NULL)
640 return sjme_error_default(error);
642 /* Process it. */
643 error = at->handler(inPool, inConstPool, inStringPool, context,
644 attrName, attrStream, attrData, attrLen);
646 /* Close stream. */
647 if (sjme_error_is(errorC = sjme_closeable_close(
648 SJME_AS_CLOSEABLE(attrStream))))
649 return sjme_error_defaultOr(error, errorC);
651 /* Failed? */
652 if (sjme_error_is(error))
653 return sjme_error_default(error);
654 return error;
657 #if defined(SJME_CONFIG_DEBUG)
658 /* Debug. */
659 sjme_message("No handler for attribute %s.", attrName);
660 #endif
662 /* None found, so ignore it. */
663 return SJME_ERROR_NONE;
666 sjme_errorCode sjme_class_parse(
667 sjme_attrInNotNull sjme_alloc_pool* inPool,
668 sjme_attrInNotNull sjme_stream_input inStream,
669 sjme_attrInNotNull sjme_stringPool inStringPool,
670 sjme_attrOutNotNull sjme_class_info* outClass)
672 sjme_errorCode error;
673 sjme_jint magic, fullVersion, i;
674 sjme_jshort major, minor, interfaceCount, fieldCount, methodCount;
675 sjme_class_version actualVersion;
676 sjme_class_poolInfo pool;
677 sjme_class_info result;
678 sjme_class_poolEntry* thisName;
679 sjme_class_poolEntry* superName;
680 sjme_class_poolEntry* interfaceName;
681 sjme_list_sjme_stringPool_string* interfaceNames;
682 sjme_list_sjme_class_fieldInfo* fields;
683 sjme_list_sjme_class_methodInfo* methods;
685 if (inPool == NULL || inStream == NULL || inStringPool == NULL ||
686 outClass == NULL)
687 return SJME_ERROR_NONE;
689 /* Make sure we can actually allocate the resultant class. */
690 result = NULL;
691 if (sjme_error_is(error = sjme_nvm_alloc(inPool,
692 sizeof(*result), SJME_NVM_STRUCT_CLASS_INFO,
693 SJME_AS_NVM_COMMONP(&result))) || result == NULL)
694 goto fail_allocResult;
696 /* Read in magic number. */
697 magic = INT32_MAX;
698 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
699 inStream, &magic)))
700 goto fail_readMagic;
702 /* It must be valid! */
703 if (magic != SJME_CLASS_MAGIC)
705 error = SJME_ERROR_INVALID_CLASS_MAGIC;
706 goto fail_badMagic;
709 /* Read in version info. */
710 minor = INT16_MAX;
711 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
712 inStream, &minor)))
713 goto fail_readMinor;
715 major = INT16_MAX;
716 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
717 inStream, &major)))
718 goto fail_readMajor;
720 /* Compose and find matching version. */
721 fullVersion = (major << 16) | (minor & 0xFFFF);
722 if (fullVersion >= SJME_CLASS_CLDC_1_0 &&
723 fullVersion <= SJME_CLASS_CLDC_1_0_MAX)
724 actualVersion = SJME_CLASS_CLDC_1_0;
725 else if (fullVersion >= SJME_CLASS_CLDC_1_1 &&
726 fullVersion <= SJME_CLASS_CLDC_1_1_MAX)
727 actualVersion = SJME_CLASS_CLDC_1_1;
728 else if (fullVersion >= SJME_CLASS_CLDC_1_8 &&
729 fullVersion <= SJME_CLASS_CLDC_1_8_MAX)
730 actualVersion = SJME_CLASS_CLDC_1_8;
732 /* Not valid. */
733 else
735 error = SJME_ERROR_INVALID_CLASS_VERSION;
736 goto fail_badVersion;
739 /* Set version. */
740 result->version = actualVersion;
742 /* Parse the constant pool. */
743 pool = NULL;
744 if (sjme_error_is(error = sjme_class_parseConstantPool(
745 inPool, inStream, inStringPool, &pool)) || pool == NULL)
746 goto fail_parsePool;
748 /* We are using this, so count it up. */
749 if (sjme_error_is(error = sjme_alloc_weakRef(pool, NULL)))
750 goto fail_countPool;
751 result->pool = pool;
753 /* Read in flags. */
754 if (sjme_error_is(error = sjme_class_classFlagsParse(
755 inStream, &result->flags)))
756 goto fail_readFlags;
758 /* Read in this name. */
759 thisName = NULL;
760 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
761 inStream, result->pool,
762 SJME_CLASS_POOL_TYPE_CLASS,
763 SJME_JNI_FALSE, &thisName)) || thisName == NULL)
764 goto fail_readThisName;
766 /* Reference it. */
767 result->name = thisName->classRef.descriptor;
768 if (sjme_error_is(error = sjme_alloc_weakRef(
769 result->name, NULL)))
770 goto fail_refThisName;
772 /* Read in super name. */
773 superName = NULL;
774 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
775 inStream, result->pool,
776 SJME_CLASS_POOL_TYPE_CLASS,
777 SJME_JNI_TRUE, &superName)))
778 goto fail_readSuperName;
780 /* Reference it, if valid. */
781 if (superName != NULL)
783 result->superName = superName->classRef.descriptor;
784 if (sjme_error_is(error = sjme_alloc_weakRef(
785 result->superName, NULL)))
786 goto fail_refSuperName;
789 /* How many interfaces are there? */
790 interfaceCount = -1;
791 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
792 inStream, &interfaceCount)) || interfaceCount < 0)
793 goto fail_readInterfaceCount;
795 /* Allocate interfaces count. */
796 interfaceNames = NULL;
797 if (sjme_error_is(error = sjme_list_alloc(inPool,
798 interfaceCount, &interfaceNames, sjme_stringPool_string, 0)) ||
799 interfaceNames == NULL)
800 goto fail_allocInterfaceNames;
801 result->interfaceNames = interfaceNames;
803 /* Read in all interfaces. */
804 for (i = 0; i < interfaceCount; i++)
806 /* Read in name. */
807 interfaceName = NULL;
808 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
809 inStream, result->pool,
810 SJME_CLASS_POOL_TYPE_CLASS,
811 SJME_JNI_FALSE, &interfaceName)) ||
812 interfaceName == NULL)
813 goto fail_readThisName;
815 /* Reference it. */
816 interfaceNames->elements[i] = interfaceName->classRef.descriptor;
817 if (sjme_error_is(error = sjme_alloc_weakRef(
818 interfaceNames->elements[i], NULL)))
819 goto fail_refThisName;
822 /* Read in field count. */
823 fieldCount = -1;
824 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
825 inStream, &fieldCount)) || fieldCount < 0)
826 goto fail_readFieldCount;
828 /* Setup list to store fields in. */
829 fields = NULL;
830 if (sjme_error_is(error = sjme_list_alloc(inPool,
831 fieldCount, &fields, sjme_class_fieldInfo, 0)) || fields == NULL)
832 goto fail_allocFields;
833 result->fields = fields;
835 /* Load in and process each field. */
836 for (i = 0; i < fieldCount; i++)
838 /* Parse each field. */
839 if (sjme_error_is(error = sjme_class_parseField(
840 inPool, inStream, result->pool, inStringPool,
841 &fields->elements[i])) ||
842 fields->elements[i] == NULL)
843 goto fail_parseField;
845 /* We are referencing this. */
846 if (sjme_error_is(error = sjme_alloc_weakRef(
847 fields->elements[i], NULL)))
848 goto fail_refField;
851 /* Read in method count. */
852 methodCount = -1;
853 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
854 inStream, &methodCount)) || methodCount < 0)
855 goto fail_readMethodCount;
857 /* Setup list to store methods in. */
858 methods = NULL;
859 if (sjme_error_is(error = sjme_list_alloc(inPool,
860 methodCount, &methods, sjme_class_methodInfo, 0)) || methods == NULL)
861 goto fail_allocMethods;
862 result->methods = methods;
864 /* Load in and process each method. */
865 for (i = 0; i < methodCount; i++)
867 /* Parse each method. */
868 if (sjme_error_is(error = sjme_class_parseMethod(
869 inPool, inStream, result->pool, inStringPool,
870 &methods->elements[i])) ||
871 methods->elements[i] == NULL)
872 goto fail_parseMethod;
874 /* Reference as we are using this. */
875 if (sjme_error_is(error = sjme_alloc_weakRef(
876 methods->elements[i], NULL)))
877 goto fail_refMethod;
880 /* Parse attributes. */
881 if (sjme_error_is(error = sjme_class_parseAttributes(
882 inPool, inStream, result->pool, inStringPool,
883 sjme_class_classAttr, result)))
884 goto fail_parseAttributes;
886 /* Success! */
887 *outClass = result;
888 return SJME_ERROR_NONE;
890 fail_parseAttributes:
891 fail_refMethod:
892 fail_parseMethod:
893 fail_allocMethods:
894 fail_readMethodCount:
895 fail_refField:
896 fail_parseField:
897 fail_allocFields:
898 fail_readFieldCount:
899 fail_allocInterfaceNames:
900 fail_readInterfaceCount:
901 fail_refSuperName:
902 fail_readSuperName:
903 fail_refThisName:
904 fail_readThisName:
905 fail_readFlags:
906 fail_countPool:
907 fail_parsePool:
908 fail_badVersion:
909 fail_readMinor:
910 fail_readMajor:
911 fail_badMagic:
912 fail_readMagic:
913 fail_initResult:
914 fail_allocResult:
915 if (result != NULL)
916 sjme_closeable_close(SJME_AS_CLOSEABLE(result));
917 return sjme_error_default(error);
920 sjme_errorCode sjme_class_parseAttributes(
921 sjme_attrInNotNull sjme_alloc_pool* inPool,
922 sjme_attrInNotNull sjme_stream_input inStream,
923 sjme_attrInNotNull sjme_class_poolInfo inConstPool,
924 sjme_attrInNotNull sjme_stringPool inStringPool,
925 sjme_attrInNotNull const sjme_class_parseAttributeHandlerInfo* handlers,
926 sjme_attrInNotNull sjme_pointer context)
928 sjme_errorCode error;
929 sjme_jshort count;
930 sjme_jint i, len;
931 sjme_class_poolEntry* name;
933 if (inPool == NULL || inStream == NULL || inConstPool == NULL ||
934 inStringPool == NULL || handlers == NULL || context == NULL)
935 return SJME_ERROR_NULL_ARGUMENTS;
937 /* Read in count. */
938 count = -1;
939 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
940 inStream, &count)) || count < 0)
941 goto fail_readCount;
943 /* Read individual attributes. */
944 for (i = 0; i < count; i++)
946 /* Read in name. */
947 name = NULL;
948 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
949 inStream, inConstPool,
950 SJME_CLASS_POOL_TYPE_UTF,
951 SJME_JNI_FALSE, &name)) || name == NULL)
952 goto fail_readName;
954 /* Read in length. */
955 len = -1;
956 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
957 inStream, &len)) || len < 0)
958 goto fail_readLen;
960 /* Stage it for stack allocations. */
961 if (sjme_error_is(error = sjme_class_parseAttribute(
962 inPool, inStream, inConstPool, inStringPool, handlers,
963 context, (sjme_lpcstr)&name->utf.utf->chars[0],
964 len)))
965 goto fail_parseSingle;
968 /* Success! */
969 return SJME_ERROR_NONE;
971 fail_parseSingle:
972 fail_readLen:
973 fail_readName:
974 fail_readCount:
975 return sjme_error_default(error);
978 sjme_errorCode sjme_class_parseConstantPool(
979 sjme_attrInNotNull sjme_alloc_pool* inPool,
980 sjme_attrInNotNull sjme_stream_input inStream,
981 sjme_attrInNotNull sjme_stringPool inStringPool,
982 sjme_attrOutNotNull sjme_class_poolInfo* outPool)
984 sjme_errorCode error;
985 sjme_jshort count;
986 sjme_jint index;
987 sjme_jbyte tag;
988 sjme_list_sjme_class_poolEntry* entries;
989 sjme_class_poolEntry* entry;
990 sjme_class_poolEntry* target;
991 sjme_stringPool_string utf;
992 sjme_class_poolInfo result;
994 if (inPool == NULL || inStream == NULL || outPool == NULL ||
995 inStringPool == NULL)
996 return SJME_ERROR_NULL_ARGUMENTS;
998 /* Make sure we can actually allocate this. */
999 result = NULL;
1000 if (sjme_error_is(error = sjme_nvm_alloc(inPool,
1001 sizeof(*result), SJME_NVM_STRUCT_POOL,
1002 SJME_AS_NVM_COMMONP(&result))) || result == NULL)
1003 goto fail_allocResult;
1005 /* Read in pool count. */
1006 count = -1;
1007 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
1008 inStream, &count)) || count < 0)
1009 goto fail_readCount;
1011 /* Invalid pool size? */
1012 if (count < 0 || count >= INT16_MAX)
1014 error = SJME_ERROR_INVALID_CLASS_POOL_COUNT;
1015 goto fail_poolCount;
1018 /* Count up by one, since zero is included! */
1019 count += 1;
1021 /* Allocate resultant entries, where they will all go. */
1022 entries = NULL;
1023 if (sjme_error_is(error = sjme_list_alloc(inPool,
1024 count, &entries, sjme_class_poolEntry, 0)) || entries == NULL)
1025 goto fail_entryList;
1026 result->pool = entries;
1028 /* Read in all entries. */
1029 /* This is a first pass since index items can refer to later entries. */
1030 for (index = 1; index < count - 1; index++)
1032 /* Which entry is being written? */
1033 entry = &entries->elements[index];
1035 /* Read in tag. */
1036 tag = -1;
1037 if (sjme_error_is(error = sjme_stream_inputReadValueJB(
1038 inStream, &tag)) || tag < 0)
1039 goto fail_readTag;
1041 /* Debug. */
1042 sjme_message("TAG: %d", tag);
1044 /* Set tag. */
1045 entry->type = tag;
1047 /* Which tag is this? */
1048 switch (tag)
1050 /* Class reference. */
1051 case SJME_CLASS_POOL_TYPE_CLASS:
1052 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
1053 inStream,
1054 &entry->classRef.descriptorIndex)))
1055 goto fail_readItem;
1056 break;
1058 /* Double value. */
1059 case SJME_CLASS_POOL_TYPE_DOUBLE:
1060 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
1061 inStream,
1062 (sjme_jint*)&entry->constDouble.value.hi)))
1063 goto fail_readItem;
1064 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
1065 inStream,
1066 (sjme_jint*)&entry->constDouble.value.lo)))
1067 goto fail_readItem;
1069 /* Skip wide index. */
1070 index++;
1071 break;
1073 /* Reference to a member. */
1074 case SJME_CLASS_POOL_TYPE_FIELD:
1075 case SJME_CLASS_POOL_TYPE_INTERFACE_METHOD:
1076 case SJME_CLASS_POOL_TYPE_METHOD:
1077 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
1078 inStream,
1079 &entry->member.inClassIndex)))
1080 goto fail_readItem;
1081 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
1082 inStream,
1083 &entry->member.nameAndTypeIndex)))
1084 goto fail_readItem;
1085 break;
1087 /* Float value. */
1088 case SJME_CLASS_POOL_TYPE_FLOAT:
1089 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
1090 inStream,
1091 (sjme_jint*)&entry->constFloat.value.value)))
1092 goto fail_readItem;
1093 break;
1095 /* Integer value. */
1096 case SJME_CLASS_POOL_TYPE_INTEGER:
1097 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
1098 inStream,
1099 (sjme_jint*)&entry->constInteger.value)))
1100 goto fail_readItem;
1101 break;
1103 /* Long value. */
1104 case SJME_CLASS_POOL_TYPE_LONG:
1105 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
1106 inStream,
1107 (sjme_jint*)&entry->constLong.value.part.hi)))
1108 goto fail_readItem;
1109 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
1110 inStream,
1111 (sjme_jint*)&entry->constLong.value.part.lo)))
1112 goto fail_readItem;
1114 /* Skip wide index. */
1115 index++;
1116 break;
1118 /* Name and type information. */
1119 case SJME_CLASS_POOL_TYPE_NAME_AND_TYPE:
1120 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
1121 inStream,
1122 &entry->nameAndType.nameIndex)))
1123 goto fail_readItem;
1124 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
1125 inStream,
1126 &entry->nameAndType.descriptorIndex)))
1127 goto fail_readItem;
1128 break;
1130 /* Constant string. */
1131 case SJME_CLASS_POOL_TYPE_STRING:
1132 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
1133 inStream,
1134 &entry->constString.valueIndex)))
1135 goto fail_readItem;
1136 break;
1138 /* UTF String. */
1139 case SJME_CLASS_POOL_TYPE_UTF:
1140 utf = NULL;
1141 if (sjme_error_is(error = sjme_stringPool_locateStream(
1142 inStringPool, inStream, &utf)) || utf == NULL)
1143 goto fail_readItem;
1145 /* Debug. */
1146 sjme_message("Read UTF: %s",
1147 utf->chars);
1149 /* Store and count up entry as we are using it now. */
1150 entry->utf.utf = utf;
1151 if (sjme_error_is(error = sjme_alloc_weakRef(
1152 utf, NULL)))
1153 goto fail_readItem;
1154 break;
1156 default:
1157 sjme_todo("Impl? %d", tag);
1158 return SJME_ERROR_NOT_IMPLEMENTED;
1162 /* Second stage item linking. */
1163 for (index = 1; index < count - 1; index++)
1165 /* Which entry is being initialized? */
1166 entry = &entries->elements[index];
1168 /* Initialize accordingly. */
1169 switch (entry->type)
1171 /* These are base elements that need no initialization. */
1172 case SJME_CLASS_POOL_TYPE_UTF:
1173 case SJME_CLASS_POOL_TYPE_INTEGER:
1174 case SJME_CLASS_POOL_TYPE_FLOAT:
1175 break;
1177 /* Skip wide element. */
1178 case SJME_CLASS_POOL_TYPE_LONG:
1179 case SJME_CLASS_POOL_TYPE_DOUBLE:
1180 index++;
1181 break;
1183 /* Class type. */
1184 case SJME_CLASS_POOL_TYPE_CLASS:
1185 if (entry->classRef.descriptorIndex <= 0 ||
1186 entry->classRef.descriptorIndex >= entries->length)
1188 error = SJME_ERROR_INVALID_CLASS_POOL_INDEX;
1189 goto fail_initItem;
1192 /* Needs to be a UTF string. */
1193 target = &entries->elements[entry->classRef.descriptorIndex];
1194 if (target->type != SJME_CLASS_POOL_TYPE_UTF)
1196 error = SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE;
1197 goto fail_initItem;
1200 /* Refer to it and count up, since we are using it. */
1201 entry->classRef.descriptor = target->utf.utf;
1202 if (sjme_error_is(error = sjme_alloc_weakRef(
1203 entry->classRef.descriptor, NULL)))
1204 goto fail_initItem;
1205 break;
1207 /* Member reference. */
1208 case SJME_CLASS_POOL_TYPE_FIELD:
1209 case SJME_CLASS_POOL_TYPE_INTERFACE_METHOD:
1210 case SJME_CLASS_POOL_TYPE_METHOD:
1211 if (entry->member.inClassIndex <= 0 ||
1212 entry->member.inClassIndex >= entries->length ||
1213 entry->member.nameAndTypeIndex <= 0 ||
1214 entry->member.nameAndTypeIndex >= entries->length)
1216 error = SJME_ERROR_INVALID_CLASS_POOL_INDEX;
1217 goto fail_initItem;
1220 /* Needs to be a class. */
1221 target = &entries->elements[entry->member.inClassIndex];
1222 if (target->type != SJME_CLASS_POOL_TYPE_CLASS)
1224 error = SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE;
1225 goto fail_initItem;
1228 /* Set class. */
1229 entry->member.inClass =
1230 (const sjme_class_poolEntryClass*)target;
1232 /* Needs to be a name and type. */
1233 target = &entries->elements[entry->member.nameAndTypeIndex];
1234 if (target->type != SJME_CLASS_POOL_TYPE_NAME_AND_TYPE)
1236 error = SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE;
1237 goto fail_initItem;
1240 /* Set name and type. */
1241 entry->member.nameAndType =
1242 (const sjme_class_poolEntryNameAndType*)target;
1243 break;
1245 case SJME_CLASS_POOL_TYPE_NAME_AND_TYPE:
1246 if (entry->nameAndType.nameIndex <= 0 ||
1247 entry->nameAndType.nameIndex >= entries->length ||
1248 entry->nameAndType.descriptorIndex <= 0 ||
1249 entry->nameAndType.descriptorIndex >= entries->length)
1251 error = SJME_ERROR_INVALID_CLASS_POOL_INDEX;
1252 goto fail_initItem;
1255 /* Needs to be UTF. */
1256 target = &entries->elements[entry->nameAndType.nameIndex];
1257 if (target->type != SJME_CLASS_POOL_TYPE_UTF)
1259 error = SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE;
1260 goto fail_initItem;
1263 /* Set name. */
1264 entry->nameAndType.name = target->utf.utf;
1265 if (sjme_error_is(error = sjme_alloc_weakRef(
1266 entry->nameAndType.name, NULL)))
1267 goto fail_initItem;
1269 /* Needs to be UTF. */
1270 target = &entries->elements[
1271 entry->nameAndType.descriptorIndex];
1272 if (target->type != SJME_CLASS_POOL_TYPE_UTF)
1274 error = SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE;
1275 goto fail_initItem;
1278 /* Set descriptor. */
1279 entry->nameAndType.descriptor = target->utf.utf;
1280 if (sjme_error_is(error = sjme_alloc_weakRef(
1281 entry->nameAndType.descriptor, NULL)))
1282 goto fail_initItem;
1283 break;
1285 /* Constant string. */
1286 case SJME_CLASS_POOL_TYPE_STRING:
1287 if (entry->constString.valueIndex <= 0 ||
1288 entry->constString.valueIndex >= entries->length)
1290 error = SJME_ERROR_INVALID_CLASS_POOL_INDEX;
1291 goto fail_initItem;
1294 /* Needs to be a UTF string. */
1295 target = &entries->elements[entry->constString.valueIndex];
1296 if (target->type != SJME_CLASS_POOL_TYPE_UTF)
1298 error = SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE;
1299 goto fail_initItem;
1302 /* Refer to it and count up, since we are using it. */
1303 entry->constString.value = target->utf.utf;
1304 if (sjme_error_is(error = sjme_alloc_weakRef(
1305 entry->constString.value, NULL)))
1306 goto fail_initItem;
1307 break;
1309 default:
1310 sjme_todo("Impl? %d", tag);
1311 return SJME_ERROR_NOT_IMPLEMENTED;
1315 /* Success! */
1316 *outPool = result;
1317 return SJME_ERROR_NONE;
1319 fail_initItem:
1320 fail_readItem:
1321 fail_readTag:
1322 fail_entryList:
1323 if (entries != NULL)
1324 sjme_alloc_free(entries);
1325 fail_poolCount:
1326 fail_readCount:
1327 fail_initCommon:
1328 fail_allocResult:
1329 if (result != NULL)
1330 sjme_closeable_close(SJME_AS_CLOSEABLE(result));
1331 return sjme_error_default(error);
1334 sjme_errorCode sjme_class_parseField(
1335 sjme_attrInNotNull sjme_alloc_pool* inPool,
1336 sjme_attrInNotNull sjme_stream_input inStream,
1337 sjme_attrInNotNull sjme_class_poolInfo inConstPool,
1338 sjme_attrInNotNull sjme_stringPool inStringPool,
1339 sjme_attrOutNotNull sjme_class_fieldInfo* outField)
1341 sjme_errorCode error;
1342 sjme_class_fieldInfo result;
1343 sjme_class_poolEntry* name;
1344 sjme_class_poolEntry* type;
1346 if (inPool == NULL || inStream == NULL || inConstPool == NULL ||
1347 outField == NULL || inStringPool == NULL)
1348 return SJME_ERROR_NULL_ARGUMENTS;
1350 /* Ensure we can allocate the result first. */
1351 result = NULL;
1352 if (sjme_error_is(error = sjme_nvm_alloc(inPool,
1353 sizeof(*result), SJME_NVM_STRUCT_FIELD_INFO,
1354 SJME_AS_NVM_COMMONP(&result))) || result == NULL)
1355 goto fail_allocResult;
1357 /* Read in flags. */
1358 if (sjme_error_is(error = sjme_class_fieldFlagsParse(
1359 inStream, &result->flags)))
1360 goto fail_readFlags;
1362 /* Read in name. */
1363 name = NULL;
1364 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
1365 inStream, inConstPool,
1366 SJME_CLASS_POOL_TYPE_UTF,
1367 SJME_JNI_FALSE, &name)) || name == NULL)
1368 goto fail_readName;
1370 /* Reference it. */
1371 result->name = name->utf.utf;
1372 if (sjme_error_is(error = sjme_alloc_weakRef(
1373 result->name, NULL)))
1374 goto fail_refName;
1376 /* Read in type. */
1377 type = NULL;
1378 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
1379 inStream, inConstPool,
1380 SJME_CLASS_POOL_TYPE_UTF,
1381 SJME_JNI_FALSE, &type)) || name == NULL)
1382 goto fail_readType;
1384 /* Reference it. */
1385 result->type = name->utf.utf;
1386 if (sjme_error_is(error = sjme_alloc_weakRef(
1387 result->type, NULL)))
1388 goto fail_refType;
1390 /* Parse attributes. */
1391 if (sjme_error_is(error = sjme_class_parseAttributes(
1392 inPool, inStream, inConstPool, inStringPool,
1393 sjme_class_fieldAttr, result)))
1394 goto fail_parseAttributes;
1396 /* Success! */
1397 *outField = result;
1398 return SJME_ERROR_NONE;
1400 fail_parseAttributes:
1401 fail_refType:
1402 fail_readType:
1403 fail_refName:
1404 fail_readName:
1405 fail_readFlags:
1406 fail_initResult:
1407 fail_allocResult:
1408 if (result != NULL)
1409 sjme_closeable_close(SJME_AS_CLOSEABLE(result));
1410 return sjme_error_default(error);
1413 sjme_errorCode sjme_class_parseMethod(
1414 sjme_attrInNotNull sjme_alloc_pool* inPool,
1415 sjme_attrInNotNull sjme_stream_input inStream,
1416 sjme_attrInNotNull sjme_class_poolInfo inConstPool,
1417 sjme_attrInNotNull sjme_stringPool inStringPool,
1418 sjme_attrInOutNotNull sjme_class_methodInfo* outMethod)
1420 sjme_errorCode error;
1421 sjme_class_methodInfo result;
1422 sjme_class_poolEntry* name;
1423 sjme_class_poolEntry* type;
1425 if (inPool == NULL || inStream == NULL || inConstPool == NULL ||
1426 outMethod == NULL || inStringPool == NULL)
1427 return SJME_ERROR_NULL_ARGUMENTS;
1429 /* Ensure we can allocate the result first. */
1430 result = NULL;
1431 if (sjme_error_is(error = sjme_nvm_alloc(inPool,
1432 sizeof(*result), SJME_NVM_STRUCT_METHOD_INFO,
1433 SJME_AS_NVM_COMMONP(&result))) || result == NULL)
1434 goto fail_allocResult;
1436 /* Read in flags. */
1437 if (sjme_error_is(error = sjme_class_methodFlagsParse(
1438 inStream, &result->flags)))
1439 goto fail_readFlags;
1441 /* Read in name. */
1442 name = NULL;
1443 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
1444 inStream, inConstPool,
1445 SJME_CLASS_POOL_TYPE_UTF,
1446 SJME_JNI_FALSE, &name)) || name == NULL)
1447 goto fail_readName;
1449 /* Reference it. */
1450 result->name = name->utf.utf;
1451 if (sjme_error_is(error = sjme_alloc_weakRef(
1452 result->name, NULL)))
1453 goto fail_refName;
1455 /* Read in type. */
1456 type = NULL;
1457 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
1458 inStream, inConstPool,
1459 SJME_CLASS_POOL_TYPE_UTF,
1460 SJME_JNI_FALSE, &type)) || name == NULL)
1461 goto fail_readType;
1463 /* Reference it. */
1464 result->type = name->utf.utf;
1465 if (sjme_error_is(error = sjme_alloc_weakRef(
1466 result->type, NULL)))
1467 goto fail_refType;
1469 /* Parse attributes. */
1470 if (sjme_error_is(error = sjme_class_parseAttributes(
1471 inPool, inStream, inConstPool, inStringPool,
1472 sjme_class_methodAttr, result)))
1473 goto fail_parseAttributes;
1475 /* Success! */
1476 *outMethod = result;
1477 return SJME_ERROR_NONE;
1479 fail_parseAttributes:
1480 fail_refType:
1481 fail_readType:
1482 fail_refName:
1483 fail_readName:
1484 fail_readFlags:
1485 fail_initResult:
1486 fail_allocResult:
1487 if (result != NULL)
1488 sjme_closeable_close(SJME_AS_CLOSEABLE(result));
1489 return sjme_error_default(error);