Read of this and super name.
[SquirrelJME.git] / nanocoat / src / classy.c
blob430c9ac351c3ed7135b86a8671d88a78a3a35789
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 "sjme/nvm/classy.h"
11 #include "sjme/debug.h"
12 #include "sjme/cleanup.h"
14 /** The magic number for classes. */
15 #define SJME_CLASS_MAGIC INT32_C(0xCAFEBABE)
17 /** CLDC 1.1 max version (JSR 30). */
18 #define SJME_CLASS_CLDC_1_0_MAX INT32_C(3080191)
20 /** CLDC 1.1 max version. (JSR 139). */
21 #define SJME_CLASS_CLDC_1_1_MAX INT32_C(3342335)
23 /** CLDC 8 max version. */
24 #define SJME_CLASS_CLDC_1_8_MAX INT32_C(3407872)
26 /** Public class. */
27 #define SJME_CLASS_ACC_PUBLIC INT16_C(0x0001)
29 /** Final class. */
30 #define SJME_CLASS_ACC_FINAL INT16_C(0x0010)
32 /** Alternative @c invokesuper logic. */
33 #define SJME_CLASS_ACC_SUPER INT16_C(0x0020)
35 /** Class is an interface. */
36 #define SJME_CLASS_ACC_INTERFACE INT16_C(0x0200)
38 /** Class is abstract. */
39 #define SJME_CLASS_ACC_ABSTRACT INT16_C(0x0400)
41 /** Class is synthetic. */
42 #define SJME_CLASS_ACC_SYNTHETIC INT16_C(0x1000)
44 /** Class is an annotation. */
45 #define SJME_CLASS_ACC_ANNOTATION INT16_C(0x2000)
47 /** Class is an enum. */
48 #define SJME_CLASS_ACC_ENUM INT16_C(0x4000)
50 static sjme_errorCode sjme_class_readClassFlags(
51 sjme_attrInNotNull sjme_stream_input inStream,
52 sjme_attrOutNotNull sjme_class_classFlags* outFlags)
54 sjme_errorCode error;
55 sjme_jshort rawFlags;
57 if (inStream == NULL || outFlags == NULL)
58 return SJME_ERROR_NULL_ARGUMENTS;
60 /* Read in flags. */
61 rawFlags = -1;
62 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
63 inStream, &rawFlags)) || rawFlags < 0)
64 return sjme_error_default(error);
66 /* Translate to bitfield. */
67 if ((rawFlags & SJME_CLASS_ACC_PUBLIC) != 0)
68 outFlags->access.public = SJME_JNI_TRUE;
69 if ((rawFlags & SJME_CLASS_ACC_FINAL) != 0)
70 outFlags->final = SJME_JNI_TRUE;
71 if ((rawFlags & SJME_CLASS_ACC_SUPER) != 0)
72 outFlags->super = SJME_JNI_TRUE;
73 if ((rawFlags & SJME_CLASS_ACC_INTERFACE) != 0)
74 outFlags->interface = SJME_JNI_TRUE;
75 if ((rawFlags & SJME_CLASS_ACC_ABSTRACT) != 0)
76 outFlags->abstract = SJME_JNI_TRUE;
77 if ((rawFlags & SJME_CLASS_ACC_SYNTHETIC) != 0)
78 outFlags->synthetic = SJME_JNI_TRUE;
79 if ((rawFlags & SJME_CLASS_ACC_ANNOTATION) != 0)
80 outFlags->annotation = SJME_JNI_TRUE;
81 if ((rawFlags & SJME_CLASS_ACC_ENUM) != 0)
82 outFlags->enumeration = SJME_JNI_TRUE;
84 /* Cannot be abstract and final. */
85 /* Annotation must be an interface. */
86 /* Interface must be abstract and not final, super, or enum */
87 if ((outFlags->abstract && outFlags->final) ||
88 (outFlags->annotation && !outFlags->interface) ||
89 (outFlags->interface && (!outFlags->abstract ||
90 outFlags->final || outFlags->super || outFlags->enumeration)))
91 return SJME_ERROR_INVALID_CLASS_FLAGS;
93 /* Success! */
94 return SJME_ERROR_NONE;
97 static sjme_errorCode sjme_class_readPoolRefIndex(
98 sjme_attrInNotNull sjme_stream_input inStream,
99 sjme_attrInNotNull sjme_class_poolInfo inClassPool,
100 sjme_attrInPositiveNonZero sjme_class_poolType desireType,
101 sjme_attrInValue sjme_jboolean canNull,
102 sjme_attrOutNotNull sjme_class_poolEntry** outEntry)
104 sjme_errorCode error;
105 sjme_jshort index;
106 sjme_class_poolEntry* result;
108 if (inStream == NULL || inClassPool == NULL || outEntry == NULL)
109 return SJME_ERROR_NULL_ARGUMENTS;
111 /* Read in index. */
112 index = -1;
113 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
114 inStream, &index)))
115 return sjme_error_default(error);
117 /* Not a valid index? */
118 if (index <= 0 || index >= inClassPool->pool->length)
119 return SJME_ERROR_INVALID_CLASS_POOL_INDEX;
121 /* Must be the desired type. */
122 result = &inClassPool->pool->elements[index];
123 if (result->type != desireType)
124 return SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE;
126 /* Success! */
127 *outEntry = result;
128 return SJME_ERROR_NONE;
131 sjme_errorCode sjme_class_parse(
132 sjme_attrInNotNull sjme_alloc_pool* inPool,
133 sjme_attrInNotNull sjme_stream_input inStream,
134 sjme_attrInNotNull sjme_stringPool inStringPool,
135 sjme_attrOutNotNull sjme_class_info* outClass)
137 sjme_errorCode error;
138 sjme_jint magic, fullVersion;
139 sjme_jshort major, minor;
140 sjme_class_version actualVersion;
141 sjme_class_poolInfo pool;
142 sjme_class_info result;
143 sjme_class_poolEntry* thisName;
144 sjme_class_poolEntry* superName;
146 if (inPool == NULL || inStream == NULL || inStringPool == NULL ||
147 outClass == NULL)
148 return SJME_ERROR_NONE;
150 /* Make sure we can actually allocate the resultant class. */
151 result = NULL;
152 if (sjme_error_is(error = sjme_alloc_weakNew(inPool,
153 sizeof(*result), NULL, NULL,
154 (sjme_pointer*)&result, NULL)) || result == NULL)
155 goto fail_allocResult;
157 /* Initialize. */
158 if (sjme_error_is(error = sjme_nvm_initCommon(
159 SJME_AS_NVM_COMMON(result),
160 SJME_NVM_STRUCT_CLASS_INFO)))
161 goto fail_initResult;
163 /* Read in magic number. */
164 magic = INT32_MAX;
165 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
166 inStream, &magic)))
167 goto fail_readMagic;
169 /* It must be valid! */
170 if (magic != SJME_CLASS_MAGIC)
172 error = SJME_ERROR_INVALID_CLASS_MAGIC;
173 goto fail_badMagic;
176 /* Read in version info. */
177 minor = INT16_MAX;
178 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
179 inStream, &minor)))
180 goto fail_readMinor;
182 major = INT16_MAX;
183 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
184 inStream, &major)))
185 goto fail_readMajor;
187 /* Compose and find matching version. */
188 fullVersion = (major << 16) | (minor & 0xFFFF);
189 if (fullVersion >= SJME_CLASS_CLDC_1_0 &&
190 fullVersion <= SJME_CLASS_CLDC_1_0_MAX)
191 actualVersion = SJME_CLASS_CLDC_1_0;
192 else if (fullVersion >= SJME_CLASS_CLDC_1_1 &&
193 fullVersion <= SJME_CLASS_CLDC_1_1_MAX)
194 actualVersion = SJME_CLASS_CLDC_1_1;
195 else if (fullVersion >= SJME_CLASS_CLDC_1_8 &&
196 fullVersion <= SJME_CLASS_CLDC_1_8_MAX)
197 actualVersion = SJME_CLASS_CLDC_1_8;
199 /* Not valid. */
200 else
202 error = SJME_ERROR_INVALID_CLASS_VERSION;
203 goto fail_badVersion;
206 /* Parse the constant pool. */
207 pool = NULL;
208 if (sjme_error_is(error = sjme_class_parseConstantPool(
209 inPool, inStream, inStringPool, &pool)) || pool == NULL)
210 goto fail_parsePool;
212 /* We are using this, so count it up. */
213 if (sjme_error_is(error = sjme_alloc_weakRef(pool, NULL)))
214 goto fail_countPool;
215 result->pool = pool;
217 /* Read in flags. */
218 if (sjme_error_is(error = sjme_class_readClassFlags(
219 inStream, &result->flags)))
220 goto fail_readFlags;
222 /* Read in this name. */
223 thisName = NULL;
224 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
225 inStream, result->pool,
226 SJME_CLASS_POOL_TYPE_CLASS,
227 SJME_JNI_FALSE, &thisName)) || thisName == NULL)
228 goto fail_readThisName;
230 /* Reference it. */
231 result->name = thisName->classRef.descriptor;
232 if (sjme_error_is(error = sjme_alloc_weakRef(
233 result->name, NULL)))
234 goto fail_refThisName;
236 /* Read in super name. */
237 superName = NULL;
238 if (sjme_error_is(error = sjme_class_readPoolRefIndex(
239 inStream, result->pool,
240 SJME_CLASS_POOL_TYPE_CLASS,
241 SJME_JNI_TRUE, &superName)))
242 goto fail_readSuperName;
244 /* Reference it, if valid. */
245 if (superName != NULL)
247 result->name = thisName->classRef.descriptor;
248 if (sjme_error_is(error = sjme_alloc_weakRef(
249 result->name, NULL)))
250 goto fail_refSuperName;
253 sjme_todo("Impl?");
254 return SJME_ERROR_NOT_IMPLEMENTED;
256 fail_refSuperName:
257 fail_readSuperName:
258 fail_refThisName:
259 fail_readThisName:
260 fail_readFlags:
261 fail_countPool:
262 fail_parsePool:
263 if (pool != NULL)
265 sjme_closeable_close(SJME_AS_CLOSEABLE(pool));
266 pool = NULL;
267 result->pool = NULL;
269 fail_badVersion:
270 fail_readMinor:
271 fail_readMajor:
272 fail_badMagic:
273 fail_readMagic:
274 fail_initResult:
275 fail_allocResult:
276 if (result != NULL)
277 sjme_closeable_close(SJME_AS_CLOSEABLE(result));
278 return sjme_error_default(error);
281 sjme_errorCode sjme_class_parseConstantPool(
282 sjme_attrInNotNull sjme_alloc_pool* inPool,
283 sjme_attrInNotNull sjme_stream_input inStream,
284 sjme_attrInNotNull sjme_stringPool inStringPool,
285 sjme_attrOutNotNull sjme_class_poolInfo* outPool)
287 sjme_errorCode error;
288 sjme_jshort count;
289 sjme_jint index;
290 sjme_jbyte tag;
291 sjme_list_sjme_class_poolEntry* entries;
292 sjme_class_poolEntry* entry;
293 sjme_class_poolEntry* target;
294 sjme_stringPool_string utf;
295 sjme_class_poolInfo result;
297 if (inPool == NULL || inStream == NULL || outPool == NULL ||
298 inStringPool == NULL)
299 return SJME_ERROR_NULL_ARGUMENTS;
301 /* Make sure we can actually allocate this. */
302 result = NULL;
303 if (sjme_error_is(error = sjme_alloc_weakNew(inPool,
304 sizeof(*result), NULL, NULL,
305 (sjme_pointer*)&result, NULL)) || result == NULL)
306 goto fail_allocResult;
308 /* Initialize it. */
309 if (sjme_error_is(error = sjme_nvm_initCommon(
310 SJME_AS_NVM_COMMON(result), SJME_NVM_STRUCT_POOL)))
311 goto fail_initCommon;
313 /* Read in pool count. */
314 count = -1;
315 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
316 inStream, &count)) || count < 0)
317 goto fail_readCount;
319 /* Invalid pool size? */
320 if (count < 0 || count >= INT16_MAX)
322 error = SJME_ERROR_INVALID_CLASS_POOL_COUNT;
323 goto fail_poolCount;
326 /* Count up by one, since zero is included! */
327 count += 1;
329 /* Allocate resultant entries, where they will all go. */
330 entries = NULL;
331 if (sjme_error_is(error = sjme_list_alloc(inPool,
332 count, &entries, sjme_class_poolEntry, 0)) || entries == NULL)
333 goto fail_entryList;
335 /* Read in all entries. */
336 /* This is a first pass since index items can refer to later entries. */
337 for (index = 1; index < count - 1; index++)
339 /* Which entry is being written? */
340 entry = &entries->elements[index];
342 /* Read in tag. */
343 tag = -1;
344 if (sjme_error_is(error = sjme_stream_inputReadValueJB(
345 inStream, &tag)) || tag < 0)
346 goto fail_readTag;
348 /* Debug. */
349 sjme_message("TAG: %d", tag);
351 /* Set tag. */
352 entry->type = tag;
354 /* Which tag is this? */
355 switch (tag)
357 case SJME_CLASS_POOL_TYPE_DOUBLE:
358 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
359 inStream,
360 (sjme_jint*)&entry->constDouble.value.hi)))
361 goto fail_readItem;
362 if (sjme_error_is(error = sjme_stream_inputReadValueJI(
363 inStream,
364 (sjme_jint*)&entry->constDouble.value.lo)))
365 goto fail_readItem;
366 break;
368 case SJME_CLASS_POOL_TYPE_CLASS:
369 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
370 inStream,
371 &entry->classRef.descriptorIndex)))
372 goto fail_readItem;
373 break;
375 /* UTF String. */
376 case SJME_CLASS_POOL_TYPE_UTF:
377 utf = NULL;
378 if (sjme_error_is(error = sjme_stringPool_locateStream(
379 inStringPool, inStream, &utf)) || utf == NULL)
380 goto fail_readItem;
382 /* Debug. */
383 sjme_message("Read UTF: %s",
384 utf->chars);
386 /* Store and count up entry as we are using it now. */
387 entry->utf.utf = utf;
388 if (sjme_error_is(error = sjme_alloc_weakRef(
389 utf, NULL)))
390 goto fail_readItem;
391 break;
393 default:
394 sjme_todo("Impl? %d", tag);
395 return SJME_ERROR_NOT_IMPLEMENTED;
399 /* Second stage item linking. */
400 for (index = 1; index < count - 1; index++)
402 /* Which entry is being initialized? */
403 entry = &entries->elements[index];
405 /* Initialize accordingly. */
406 switch (entry->type)
408 /* These are base elements that need no initialization. */
409 case SJME_CLASS_POOL_TYPE_UTF:
410 case SJME_CLASS_POOL_TYPE_INTEGER:
411 case SJME_CLASS_POOL_TYPE_FLOAT:
412 case SJME_CLASS_POOL_TYPE_LONG:
413 case SJME_CLASS_POOL_TYPE_DOUBLE:
414 break;
416 /* Class type. */
417 case SJME_CLASS_POOL_TYPE_CLASS:
418 if (entry->classRef.descriptorIndex <= 0 ||
419 entry->classRef.descriptorIndex >= entries->length)
421 error = SJME_ERROR_INVALID_CLASS_POOL_INDEX;
422 goto fail_initItem;
425 /* Need to be a UTF string. */
426 target = &entries->elements[entry->classRef.descriptorIndex];
427 if (target->type != SJME_CLASS_POOL_TYPE_UTF)
429 error = SJME_ERROR_WRONG_CLASS_POOL_INDEX_TYPE;
430 goto fail_initItem;
433 /* Refer to it and count up, since we are using it. */
434 entry->classRef.descriptor = target->utf.utf;
435 if (sjme_error_is(error = sjme_alloc_weakRef(
436 entry->classRef.descriptor, NULL)))
437 goto fail_initItem;
438 break;
440 default:
441 sjme_todo("Impl? %d", tag);
442 return SJME_ERROR_NOT_IMPLEMENTED;
446 /* Setup details. */
447 result->pool = entries;
449 /* Success! */
450 *outPool = result;
451 return SJME_ERROR_NONE;
453 fail_initItem:
454 fail_readItem:
455 fail_readTag:
456 fail_entryList:
457 if (entries != NULL)
458 sjme_alloc_free(entries);
459 fail_poolCount:
460 fail_readCount:
461 fail_initCommon:
462 fail_allocResult:
463 if (result != NULL)
464 sjme_closeable_close(SJME_AS_CLOSEABLE(result));
465 return sjme_error_default(error);