int load_module_info (struct prx *p) { struct prx_modinfo *info; uint32 offset; p->modinfo = NULL; if (p->phnum > 0) offset = p->programs[0].paddr & 0x7FFFFFFF; else { error (__FILE__ ": can't find module info for PRX"); return 0; } info = (struct prx_modinfo *) xmalloc (sizeof (struct prx_modinfo)); p->modinfo = info; info->attributes = read_uint16_le (&p->data[offset]); info->version = read_uint16_le (&p->data[offset+2]); info->name = (const char *) &p->data[offset+4]; info->gp = read_uint32_le (&p->data[offset+32]); info->expvaddr = read_uint32_le (&p->data[offset+36]); info->expvaddrbtm = read_uint32_le (&p->data[offset+40]); info->impvaddr = read_uint32_le (&p->data[offset+44]); info->impvaddrbtm = read_uint32_le (&p->data[offset+48]); info->imports = NULL; info->exports = NULL; if (!check_module_info (p)) return 0; if (!load_module_imports (p)) return 0; if (!load_module_exports (p)) return 0; return 1; }
static int load_module_exports (struct prx *p) { uint32 i = 0, offset; struct prx_modinfo *info = p->modinfo; if (!info->expvaddr) return 1; info->exports = (struct prx_export *) xmalloc (info->numexports * sizeof (struct prx_export)); memset (info->exports, 0, info->numexports * sizeof (struct prx_export)); offset = prx_translate (p, info->expvaddr); for (i = 0; i < info->numexports; i++) { struct prx_export *exp = &info->exports[i]; exp->namevaddr = read_uint32_le (&p->data[offset]); exp->flags = read_uint32_le (&p->data[offset+4]); exp->size = p->data[offset+8]; exp->nvars = p->data[offset+9]; exp->nfuncs = read_uint16_le (&p->data[offset+10]); exp->expvaddr = read_uint32_le (&p->data[offset+12]); if (!check_module_export (p, i)) return 0; if (exp->namevaddr) exp->name = (const char *) &p->data[prx_translate (p, exp->namevaddr)]; else exp->name = "syslib"; if (!load_module_export (p, exp)) return 0; offset += exp->size << 2; } return 1; }
static int load_module_imports (struct prx *p) { uint32 i = 0, offset; struct prx_modinfo *info = p->modinfo; if (!info->impvaddr) return 1; info->imports = (struct prx_import *) xmalloc (info->numimports * sizeof (struct prx_import)); memset (info->imports, 0, info->numimports * sizeof (struct prx_import)); offset = prx_translate (p, info->impvaddr); for (i = 0; i < info->numimports; i++) { struct prx_import *imp = &info->imports[i]; imp->namevaddr = read_uint32_le (&p->data[offset]); imp->flags = read_uint32_le (&p->data[offset+4]); imp->size = p->data[offset+8]; imp->nvars = p->data[offset+9]; imp->nfuncs = read_uint16_le (&p->data[offset+10]); imp->nidsvaddr = read_uint32_le (&p->data[offset+12]); imp->funcsvaddr = read_uint32_le (&p->data[offset+16]); if (imp->nvars) imp->varsvaddr = read_uint32_le (&p->data[offset+20]); if (!check_module_import (p, i)) return 0; if (imp->namevaddr) imp->name = (const char *) &p->data[prx_translate (p, imp->namevaddr)]; else imp->name = NULL; if (!load_module_import (p, imp)) return 0; offset += imp->size << 2; } return 1; }
static int load_module_import (struct prx *p, struct prx_import *imp) { uint32 i, offset; if (imp->nfuncs) { imp->funcs = (struct prx_function *) xmalloc (imp->nfuncs * sizeof (struct prx_function)); offset = prx_translate (p, imp->nidsvaddr); for (i = 0; i < imp->nfuncs; i++) { struct prx_function *f = &imp->funcs[i]; f->nid = read_uint32_le (&p->data[offset + 4 * i]); f->vaddr = imp->funcsvaddr + 8 * i; f->libname = imp->name; f->name = NULL; f->numargs = -1; f->pfunc = NULL; } } if (imp->nvars) { imp->vars = (struct prx_variable *) xmalloc (imp->nvars * sizeof (struct prx_variable)); offset = prx_translate (p, imp->varsvaddr); for (i = 0; i < imp->nvars; i++) { struct prx_variable *v = &imp->vars[i]; v->nid = read_uint32_le (&p->data[offset + 8 * i + 4]); v->vaddr = read_uint32_le (&p->data[offset + 8 * i]); v->libname = imp->name; v->name = NULL; } } return 1; }
static void parse_cliloc(const char *p, const char *end) { int a = read_uint32_le(&p, end); int b = read_uint16_le(&p, end); const char *start = p; // first go through it one pass to count the number of strings and total string size int string_count = 0; int total_string_size = 0; while(p < end) { read_uint32_le(&p, end); read_uint8(&p, end); int length = read_uint16_le(&p, end); p += length; if (length > 0) { string_count += 1; total_string_size += length + 1; // include null terminator } } // rewind p = start; cliloc_entry_count = string_count; cliloc_entries = (ml_cliloc_entry *)malloc(sizeof(ml_cliloc_entry) * string_count); int next_index = 0; while(p < end) { int id = read_sint32_le(&p, end); read_uint8(&p, end); int length = read_uint16_le(&p, end); if (length > 0) { ml_cliloc_entry *entry = &cliloc_entries[next_index]; entry->id = id; char *s = (char *)malloc(length+1); s[length-1] = '\0'; read_ascii_fixed(&p, end, s, length); entry->s = s; next_index += 1; } } for (int i = 0; i < string_count; i++) { ml_cliloc_entry *entry = &cliloc_entries[i]; //printf("%d, %d: %s\n", i, entry->id, entry->s); } }
static void parse_tiledata(const char *p, const char *end) { int remaining_bytes = (int)(end - p); int block_count = (remaining_bytes-512*32*(8+2+20)) / (4 + 32*(8+1+1+4+2+2+2+1+20)); item_data_entry_count = 32*block_count; tile_datas = (ml_tile_data_entry *)malloc(512*32*sizeof(ml_tile_data_entry)); item_datas = (ml_item_data_entry *)malloc(item_data_entry_count * sizeof(ml_item_data_entry)); // 512*4 + 512*32*(8+2+20) bytes // first, 512 land data for (int i = 0; i < 512*32; i++) { // every 32 entries have a header of unknown use if (i % 32 == 0) { read_uint32_le(&p, end); } ml_tile_data_entry *tile_data = &tile_datas[i]; tile_data->flags = read_uint64_le(&p, end); tile_data->texture = read_uint16_le(&p, end); // hmm can this be used instead of the rotation of land gfx? read_ascii_fixed(&p, end, tile_data->name, 20); //printf("%d: %08llx %d %s\n", i, (unsigned long long)flags, texture, name); } int i = 0; while (p < end) { // every 32 entries have a header of unknown use if (i % 32 == 0) { read_uint32_le(&p, end); } ml_item_data_entry *item_data = &item_datas[i]; item_data->flags = read_uint64_le(&p, end); item_data->weight = read_uint8(&p, end); item_data->quality = read_uint8(&p, end); item_data->quantity = read_uint32_le(&p, end); item_data->animation = read_uint16_le(&p, end); read_uint16_le(&p, end); read_uint16_le(&p, end); item_data->height = read_uint8(&p, end); read_ascii_fixed(&p, end, item_data->name, 20); //printf("%d: %08llx %d %s\n", i, (unsigned long long)flags, animation, name); i += 1; } }
static void parse_multi(const char *p, const char *end, ml_multi **m) { int num_bytes = (int)(end - p); int item_count = num_bytes / 16; int multi_size = sizeof(ml_multi) + item_count * sizeof((*m)->items[0]); *m = (ml_multi *)malloc(multi_size); (*m)->item_count = item_count; for (int i = 0; i < item_count; i++) { (*m)->items[i].item_id = read_uint16_le(&p, end); (*m)->items[i].x = read_sint16_le(&p, end); (*m)->items[i].y = read_sint16_le(&p, end); (*m)->items[i].z = read_sint16_le(&p, end); (*m)->items[i].visible = read_uint32_le(&p, end); read_uint32_le(&p, end); } }
static int load_module_export (struct prx *p, struct prx_export *exp) { uint32 i, offset, disp; offset = prx_translate (p, exp->expvaddr); disp = 4 * (exp->nfuncs + exp->nvars); if (exp->nfuncs) { exp->funcs = (struct prx_function *) xmalloc (exp->nfuncs * sizeof (struct prx_function)); for (i = 0; i < exp->nfuncs; i++) { struct prx_function *f = &exp->funcs[i]; f->vaddr = read_uint32_le (&p->data[offset + disp]); f->nid = read_uint32_le (&p->data[offset]); f->name = NULL; f->libname = exp->name; f->numargs = -1; f->pfunc = NULL; offset += 4; if (exp->namevaddr == 0) { f->name = resolve_syslib_nid (f->nid); } } } if (exp->nvars) { exp->vars = (struct prx_variable *) xmalloc (exp->nvars * sizeof (struct prx_variable)); for (i = 0; i < exp->nvars; i++) { struct prx_variable *v = &exp->vars[i]; v->vaddr = read_uint32_le (&p->data[offset + disp]); v->nid = read_uint32_le (&p->data[offset]); v->name = NULL; v->libname = exp->name; offset += 4; if (exp->namevaddr == 0) { v->name = resolve_syslib_nid (v->nid); } } } return 1; }
static void parse_unicode_font_metadata(const char *p, const char *end, ml_font_metadata *font_metadata) { const char *start = p; uint32_t char_data_start[0x10000]; for (int i = 0; i < 0x10000; i++) { char_data_start[i] = read_uint32_le(&p, end); //printf("%d: %d\n", i, char_data_start[i]); } int max_width = 0; int max_height = 0; int non_nulls = 0; int total_pixels = 0; for (int i = 0; i < 0x10000; i++) { p = start + char_data_start[i]; if (p == end) // special case for broken unifont3.mul... { p -= 4; } int kerning = read_sint8(&p, end); int baseline = read_sint8(&p, end); int width = read_sint8(&p, end); int height = read_sint8(&p, end); if (width > max_width ) max_width = width ; if (height > max_height) max_height = height; font_metadata->chars[i].kerning = kerning; font_metadata->chars[i].baseline = baseline; font_metadata->chars[i].width = width; font_metadata->chars[i].height = height; total_pixels += width * height; if (char_data_start[i] != 0) { non_nulls += 1; } } //printf("%d %d %d %d\n", non_nulls, total_pixels, max_width, max_height); }
static void parse_gump(const char *p, const char *end, int width, int height, ml_gump **g) { int line_start_offsets[512]; assert(height < sizeof(line_start_offsets)/sizeof(line_start_offsets[0])); const char *start = p; for (int i = 0; i < height; i++) { line_start_offsets[i] = read_uint32_le(&p, end); //printf("%d %d\n", i, line_start_offsets[i]); } int gump_size = sizeof(ml_gump) + 2 * width * height; *g = (ml_gump *)malloc(gump_size); (*g)->width = width; (*g)->height = height; uint16_t *target_data = (*g)->data; memset(target_data, 0, 2 * width * height); for (int i = 0; i < height; i++) { uint16_t *w = target_data + i * width; p = start + line_start_offsets[i] * 4; int accum_length = 0; while (accum_length < width) { uint16_t color = read_uint16_le(&p, end); int length = read_uint16_le(&p, end); for (int j = 0; j < length; j++) { *w = color; // set alpha... if (*w) { *w |= 0x8000; } w += 1; } accum_length += length; } } }
static void parse_hues(const char *p, const char *end) { hues = (ml_hue *)malloc(sizeof(ml_hue)*8*375); for (int i = 0; i < 8*375; i++) { // every eighth hue is prepended by an unknown header if (i % 8 == 0) { read_uint32_le(&p, end); } ml_hue *hue = &hues[i]; for (int j = 0; j < 32; j++) { hue->colors[j] = read_uint16_le(&p, end); } hue->start_color = read_uint16_le(&p, end); hue->end_color = read_uint16_le(&p, end); read_ascii_fixed(&p, end, hue->name, 20); //printf("%d: %s %04x %04x\n", i, name, start_color, end_color); } }
static void parse_render_unicode_font_string(const char *p, const char *end, int font_id, std::wstring s, ml_art **res) { const char *start = p; uint32_t char_data_start[0x10000]; for (int i = 0; i < 0x10000; i++) { char_data_start[i] = read_uint32_le(&p, end); } int str_len = s.length(); const int space_width = 3; int art_width; int art_height; ml_get_font_string_dimensions(font_id, s, &art_width, &art_height); int art_size = sizeof(ml_art) + 2 * art_width * art_height; *res = (ml_art *)malloc(art_size); (*res)->width = art_width; (*res)->height = art_height; uint16_t *target_data = (*res)->data; memset(target_data, 0, 2 * art_width * art_height); int offset_x = 0; for (int i = 0; i < str_len; i++) { wchar_t c = s[i]; assert(c >= 0 && c < 0x10000); p = start + char_data_start[c]; if (p == end) // special case for broken unifont3.mul... { p -= 4; } int kerning = read_uint8(&p, end); int baseline = read_uint8(&p, end); int width = read_uint8(&p, end); int height = read_uint8(&p, end); // special handle space if (c == ' ') { width = space_width; } else { for (int j = 0; j < art_height; j++) { uint16_t *w = target_data + offset_x + j * art_width; if (j >= baseline && j < baseline + height) { uint8_t raw_data; for (int x = 0; x < width; x++) { if ((x % 8) == 0) { raw_data = read_uint8(&p, end); } if (raw_data & 0x80) { *w++ = 0xffff; } else { *w++ = 0x0000; } raw_data <<= 1; } } } } //printf("'%c' width: %d\n", c, width); offset_x += width+1; } //printf("total width, height: %d, %d\n", art_width, art_height); }
static void parse_anim(const char *p, const char *end, ml_anim **animation) { //printf("parsing... offset: %d, length: %d\n", offset, length); //p += offset; uint16_t palette[0x100]; int frame_count; int frame_start_offsets[64]; int total_frames_size; for (int i = 0; i < 0x100; i++) { palette[i] = read_uint16_le(&p, end); // set alpha if (palette[i]) { palette[i] |= 0x8000; } //printf("palette %d %d\n", i, palette[i]); } const char *payload_start = p; frame_count = read_sint32_le(&p, end); assert(frame_count <= sizeof(frame_start_offsets)/sizeof(frame_start_offsets[0])); for (int i = 0; i < frame_count; i++) { frame_start_offsets[i] = read_sint32_le(&p, end); //printf("offset %d %d\n", i, frame_start_offsets[i]); } total_frames_size = 0; for (int i = 0; i < frame_count; i++) { if (frame_start_offsets[i] != 0) { p = payload_start + frame_start_offsets[i] + 4; int width = read_sint16_le(&p, end); int height = read_sint16_le(&p, end); total_frames_size += 2 * width * height; } } //printf("frames size: %d\n", total_frames_size); int anim_meta_data_size = sizeof(ml_anim) + frame_count * sizeof((*animation)->frames[0]); int anim_size = anim_meta_data_size + total_frames_size; //printf("this animation is %d bytes\n", anim_size); *animation = (ml_anim *)malloc(anim_size); ml_anim *anim = *animation; anim->frame_count = frame_count; char *frame_data_start = ((char *)anim) + anim_meta_data_size; int offset_accum = 0; for (int i = 0; i < frame_count; i++) { //printf("frame %d of %d\n", i, frame_count); p = payload_start + frame_start_offsets[i]; int center_x = 0; int center_y = 0; int width = 0; int height = 0; if (frame_start_offsets[i] != 0) { center_x = read_sint16_le(&p, end); center_y = read_sint16_le(&p, end); width = read_sint16_le(&p, end); height = read_sint16_le(&p, end); } anim->frames[i].center_x = center_x; anim->frames[i].center_y = center_y; anim->frames[i].width = width; anim->frames[i].height = height; anim->frames[i].data = (uint16_t *)(frame_data_start + offset_accum); offset_accum += 2 * width * height; uint16_t *target_data = anim->frames[i].data; memset(target_data, 0, 2 * width * height); //printf("%d %d %d %d\n", center_x, center_y, width, height); if (frame_start_offsets[i] != 0) { while (true) { uint32_t header = read_uint32_le(&p, end); //printf("header %08x\n", header); if (header == 0x7FFF7FFFul) { // finished... break; } int offset_x = ((header >> 22) ^ 0x200) - 0x200; int offset_y = (((header >> 12) & 0x3ff) ^ 0x200) - 0x200; int run = header & 0xfff; int start_x = center_x + offset_x; int start_y = center_y + height + offset_y; uint16_t *w = (uint16_t *)&target_data[start_x + start_y * width]; uint16_t *wend = w + width * height; //printf("%d %d\n", width, height); //printf("%d %d %d\n", start_x, start_y, run); for (int j = 0; j < run; j++) { assert(w < wend); *w = palette[read_uint8(&p, end)]; w += 1; } //printf("%d %d %d\n", start_x, start_y, run); } } } // when we are done we should have written every byte we allocated assert(anim_meta_data_size + offset_accum == anim_size); //printf("read %d\n", (int)((p - payload_start) + 0x200)); }