uint32_t write_text_hash_table (rRCOFile_writehelper * rcoH, rRCOEntry * entry, rRCOFile * rco) { uint32_t num = ((rRCOTextEntry *) entry->extra)->numIndexes; if (!num) return 0; uint32_t *hashTable = (uint32_t *) malloc (num * sizeof (uint32_t)); memset (hashTable, 0, num * sizeof (uint32_t)); uint32_t i; for (i = 0; i < num; i++) { RCOTextIndex *ti = &(((rRCOTextEntry *) entry->extra)->indexes[i]); if (ti->labelOffset != RCO_NULL_PTR) { uint32_t *hashPtr = &hashTable[calc_hash (rco->labels + ti->labelOffset, hashTable, num)]; *hashPtr = entry->offset + sizeof (RCOEntry) + sizeof (RCOTextEntry) + i * sizeof (RCOTextIndex); if (rco->eSwap) *hashPtr = ENDIAN_SWAP (*hashPtr); } } // write it rco_fwrite (rcoH, hashTable, num * sizeof (uint32_t)); free (hashTable); return num; }
static MsChunk* ani_load_chunk(MsAni *ani) { DATA32 chunk_id, chunk_size, dummy; MsChunk *chunk; if (ani->cp >= ani->data_size + 8) return NULL; ani->cp += ani_read_int32(ani->fp, &chunk_id, 1); while (chunk_id == 0x5453494C) { D("Skipping LIST chunk header ...\n"); ani->cp += ani_read_int32(ani->fp, &dummy, 1); ani->cp += ani_read_int32(ani->fp, &dummy, 1); ani->cp += ani_read_int32(ani->fp, &chunk_id, 1); } ani->cp += ani_read_int32(ani->fp, &chunk_size, 1); /* Pad it up to word length */ if (chunk_size % 2) chunk_size += (2 - (chunk_size % 2)); chunk = (MsChunk*) calloc(1, sizeof(MsChunk*) + 2 * sizeof(DATA32) + chunk_size); if (!chunk) { D("Warning, failed to allocate ANI chunk of size %d\n", sizeof(MsChunk*) + 2 * sizeof(DATA32) + chunk_size); return NULL; } chunk->chunk_id = chunk_id; chunk->chunk_size = chunk_size; chunk_id = ENDIAN_SWAP(chunk_id); D("Loaded chunk with ID '%c%c%c%c' and length %i\n", ((char*)&chunk_id)[0], ((char*)&chunk_id)[1], ((char*)&chunk_id)[2], ((char*)&chunk_id)[3], chunk_size); ani->cp += ani_read_int8(ani->fp, &chunk->data, chunk_size); return chunk; }
static int ani_read_int32 (FILE *fp, DATA32 *data, int count) { int i, total; total = count; if (count > 0) { ani_read_int8 (fp, (DATA8*) data, count * 4); for (i = 0; i < count; i++) data[i] = ENDIAN_SWAP(data[i]); } return total * 4; }
void do_hashing (rRCOEntry * entry, rRCOFile * rco, uint8_t recurse, uint32_t * hashTable, uint32_t hashTableSize) { if (entry->labelOffset != RCO_NULL_PTR) { uint32_t *hashPtr = &hashTable[calc_hash (rco->labels + entry->labelOffset, hashTable, hashTableSize)]; *hashPtr = entry->offset; if (rco->eSwap) *hashPtr = ENDIAN_SWAP (*hashPtr); } if (recurse) { rRCOEntry *rcoNode; for (rcoNode = entry->firstChild; rcoNode; rcoNode = rcoNode->next) do_hashing (rcoNode, rco, recurse, hashTable, hashTableSize); } }
SRC_REL(ABSOLUTE), SRC_SEL_X(SQ_SEL_X), MEGA_FETCH_COUNT(16)), VTX_DWORD1_GPR(DST_GPR(0), DST_REL(0), DST_SEL_X(SQ_SEL_X), DST_SEL_Y(SQ_SEL_Y), DST_SEL_Z(SQ_SEL_Z), DST_SEL_W(SQ_SEL_W), USE_CONST_FIELDS(0), DATA_FORMAT(FMT_32_32_32_32_FLOAT), NUM_FORMAT_ALL(SQ_NUM_FORMAT_SCALED), FORMAT_COMP_ALL(SQ_FORMAT_COMP_SIGNED), SRF_MODE_ALL(SRF_MODE_ZERO_CLAMP_MINUS_ONE)), VTX_DWORD2(OFFSET(0), ENDIAN_SWAP(SQ_ENDIAN_NONE), CONST_BUF_NO_STRIDE(0), MEGA_FETCH(1)), VTX_DWORD_PAD }; /* pixel shader 00 TEX: ADDR(2) CNT(1) VALID_PIX 0 SAMPLE R0, v0.xy01, t0, s0 1 SAMPLE R1, v0.xy01, t0, s1 01 EXP_DONE: PIX0, R0
// returns next entry offset (like the length, but the last entry returns zero) // // - doesn't really have much meaning - it's primarily used for internal // purposes uint32_t write_entry (rRCOFile_writehelper * rcoH, rRCOEntry * entry, uint32_t parentOffset, uint32_t prevOffset, uint8_t isLastSubentry) { uint32_t fPos = rcowrite_ftell (rcoH); entry->offset = fPos; RCOEntry re; re.typeId = (entry->id << 8) | (entry->type); re.blank = 0; re.labelOffset = entry->labelOffset; if (entry->type == 0 || ((entry->id == RCO_TABLE_MAIN || entry->id == RCO_TABLE_ANIM) && entry->type == 1)) { // a "parent" entry re.eHeadSize = 0; re.entrySize = sizeof (RCOEntry); // anim main tables have a prevOffset though :/ (object main tables don't) if (entry->id == RCO_TABLE_ANIM) re.prevEntryOffset = prevOffset; else re.prevEntryOffset = 0; } else { re.eHeadSize = sizeof (RCOEntry); re.entrySize = 0; // not sure why, but it appears that "non-main" object/anim entries also // have the total size of the entry stored in entrySize; only done if the // entry has subentries if ((entry->id == RCO_TABLE_OBJ || entry->id == RCO_TABLE_ANIM) && entry->numSubentries) { int lenNum = (entry->id == RCO_TABLE_OBJ ? RCO_OBJ_EXTRA_LEN_NUM : RCO_ANIM_EXTRA_LEN_NUM); const int *lenArray; lenArray = (entry->id == RCO_TABLE_OBJ ? RCO_OBJ_EXTRA_LEN : RCO_ANIM_EXTRA_LEN); if (entry->type <= lenNum && lenArray[entry->type] > 0) re.entrySize = sizeof (RCOEntry) + lenArray[entry->type] * sizeof (uint32_t); } re.prevEntryOffset = prevOffset; } re.numSubentries = entry->numSubentries; re.parentTblOffset = fPos - parentOffset; re.blanks[0] = re.blanks[1] = 0; re.nextEntryOffset = 0; if (entry->rco->eSwap) es_rcoEntry (&re); rco_fwrite (rcoH, &re, sizeof (re)); if (entry->rco->eSwap) es_rcoEntry (&re); // extra items here switch (entry->id) { case RCO_TABLE_VSMX: if (entry->type == 1) { RCOVSMXEntry rve; rve.offset = 0; rve.length = entry->srcLenUnpacked; if (entry->rco->eSwap) es_rcoVsmxEntry (&rve); rco_fwrite (rcoH, &rve, sizeof (rve)); uint32_t vsmxLen = 0; uint8_t *bufferVSMX = (uint8_t *) read_resource (entry, &vsmxLen); if (bufferVSMX) { if (vsmxLen == entry->srcLenUnpacked) rco_fwrite (rcoH, bufferVSMX, vsmxLen); free (bufferVSMX); } } break; case RCO_TABLE_TEXT: if (entry->type == 1) { RCOTextEntry rte; rRCOTextEntry *src = (rRCOTextEntry *) entry->extra; uint32_t i; rte.lang = src->lang; rte.format = src->format; rte.numIndexes = src->numIndexes; if (entry->rco->eSwap) es_rcoTextEntry (&rte); rco_fwrite (rcoH, &rte, sizeof (rte)); // instead of blindly dumping src->indexes, we'll "pack" the entries // together (allows source file to be of a different format, ie INI) uint32_t entryTextOffset = rcoH->sizeText; for (i = 0; i < src->numIndexes; i++) { RCOTextIndex rti; rti.labelOffset = src->indexes[i].labelOffset; rti.length = src->indexes[i].length; // Sony is doing some weird stuff :| if (src->indexes[i].offset == RCO_NULL_PTR) rti.offset = RCO_NULL_PTR; else if (rti.length) { if (rcoH->tables) // compressing - we need to make the offset // relative to the section of text data rti.offset = rcoH->sizeText - entryTextOffset; else rti.offset = rcoH->sizeText; } else // TODO: experimental (it seems that Sony likes // // sticking in a weird pointer for a blank text // entry) rti.offset = entryTextOffset - 1; rcoH->sizeText += rti.length; // doesn't have trailing null, so no +1 // // needed // align to 4 byte boundary rcoH->sizeText = ALIGN_TO_4 (rcoH->sizeText); if (entry->rco->eSwap) es_rcoTextIndex (&rti); rco_fwrite (rcoH, &rti, sizeof (rti)); } if (rcoH->sizeText - entryTextOffset > rcoH->longestLangData) rcoH->longestLangData = rcoH->sizeText - entryTextOffset; } break; case RCO_TABLE_IMG: case RCO_TABLE_MODEL: if (entry->type == 1) { rRCOImgModelEntry *srcExtra = (rRCOImgModelEntry *) entry->extra; RCOImgModelEntry rie; uint32_t *totalResSize = (entry->id == RCO_TABLE_IMG ? &(rcoH->sizeImg) : &(rcoH->sizeModel)); rie.format = srcExtra->format; // we've already got the compression info done here, so just copy it // over rie.compression = entry->srcCompression | (srcExtra->unkCompr << 8); rie.offset = *totalResSize; rie.sizeUnpacked = entry->srcLenUnpacked; rie.sizePacked = entry->srcLen; *totalResSize += rie.sizePacked; // align to 4 byte boundary *totalResSize = ALIGN_TO_4 (*totalResSize); if (entry->rco->eSwap) es_rcoImgModelEntry (&rie); // we'll omit the packed length value if this is an uncompressed entry if (entry->rco->ps3) { // PS3 image quirk uint32_t one = ENDIAN_SWAP (1); rco_fwrite (rcoH, &rie, sizeof (rie) - sizeof (uint32_t)); rco_fwrite (rcoH, &one, sizeof (one)); if (entry->srcCompression != RCO_DATA_COMPRESSION_NONE) rco_fwrite (rcoH, &rie.sizeUnpacked, sizeof (rie.sizeUnpacked)); } else { rco_fwrite (rcoH, &rie, sizeof (rie) - (entry->srcCompression == RCO_DATA_COMPRESSION_NONE ? sizeof (uint32_t) : 0)); } } break; case RCO_TABLE_SOUND: if (entry->type != 0) { rRCOSoundEntry *srcExtra = (rRCOSoundEntry *) entry->extra; RCOSoundEntry rse; uint32_t rseOffset; rse.format = srcExtra->format; rseOffset = rse.offset = rcoH->sizeSound; rse.channels = srcExtra->channels; rse.sizeTotal = entry->srcLenUnpacked; rcoH->sizeSound += rse.sizeTotal; // align to 4 byte boundary rcoH->sizeSound = ALIGN_TO_4 (rcoH->sizeSound); if (entry->rco->eSwap) es_rcoSoundEntry (&rse); rco_fwrite (rcoH, &rse, sizeof (rse)); // write size/offset pairs uint32_t i; // TODO: might actually restrict this to two channels later on for (i = 0; i < srcExtra->channels; i++) { uint32_t stuffToWrite[] = { srcExtra->channelData[i * 2], srcExtra->channelData[i * 2 + 1] + rseOffset }; if (entry->rco->eSwap) { stuffToWrite[0] = ENDIAN_SWAP (stuffToWrite[0]); stuffToWrite[1] = ENDIAN_SWAP (stuffToWrite[1]); } rco_fwrite (rcoH, stuffToWrite, sizeof (stuffToWrite)); } if (srcExtra->channels < 2) { // we'll write an extra blank channel, complying with how Sony's RCO // tools work uint32_t stuffToWrite[] = { 0, RCO_NULL_PTR }; uint32_t i; // actually, the following is unnecessary, but we'll keep it here for // // reference sake if (entry->rco->eSwap) { stuffToWrite[0] = ENDIAN_SWAP (stuffToWrite[0]); stuffToWrite[1] = ENDIAN_SWAP (stuffToWrite[1]); } for (i = srcExtra->channels; i < 2; i++) rco_fwrite (rcoH, &stuffToWrite, sizeof (uint32_t) * 2); } } break; case RCO_TABLE_FONT: if (entry->type == 1) { RCOFontEntry rfe; rRCOFontEntry *srcExtra = (rRCOFontEntry *) entry->extra; rfe.format = srcExtra->format; rfe.compression = srcExtra->compression; rfe.unknown = srcExtra->unknown; rfe.unknown2 = srcExtra->unknown2; if (entry->rco->eSwap) es_rcoFontEntry (&rfe); rco_fwrite (rcoH, &rfe, sizeof (rfe)); } break; case RCO_TABLE_OBJ: case RCO_TABLE_ANIM: if (entry->type != 0) { int lenNum; lenNum = (entry->id == RCO_TABLE_OBJ ? RCO_OBJ_EXTRA_LEN_NUM : RCO_ANIM_EXTRA_LEN_NUM); const int *lenArray; lenArray = (entry->id == RCO_TABLE_OBJ ? RCO_OBJ_EXTRA_LEN : RCO_ANIM_EXTRA_LEN); // just allocate space because we need to fix this later on if (entry->type <= lenNum && lenArray[entry->type] > 0) { uint32_t anAwesomeVariable = lenArray[entry->type]; while (anAwesomeVariable--) rco_fwrite (rcoH, &anAwesomeVariable, sizeof (anAwesomeVariable)); } else { // TODO: do something if type is unknown } } break; } // subentries uint32_t nextOffset = 0; rRCOEntry *rcoNode; for (rcoNode = entry->firstChild; rcoNode; rcoNode = rcoNode->next) { nextOffset = write_entry (rcoH, rcoNode, fPos, nextOffset, (rcoNode->next ? FALSE : TRUE)); } // write nextEntryOffset if (!isLastSubentry) { uint32_t curPos = rcowrite_ftell (rcoH); re.nextEntryOffset = curPos - fPos; rcowrite_fseek (rcoH, fPos); if (entry->rco->eSwap) es_rcoEntry (&re); rco_fwrite (rcoH, &re, sizeof (re)); if (entry->rco->eSwap) es_rcoEntry (&re); rcowrite_fseek (rcoH, curPos); } return re.nextEntryOffset; }
void rco_write_fix_refs (rRCOEntry * parent, rRCOFile_writehelper * rcoH, rRCOFile * rco, const int *lenArray, const int lenNum, uint8_t isObj) { rRCOEntry *rcoNode; for (rcoNode = parent->firstChild; rcoNode; rcoNode = rcoNode->next) { rcowrite_fseek (rcoH, rcoNode->offset + sizeof (RCOEntry)); uint32_t j, j2; uint8_t *extraPtr = (uint8_t *) rcoNode->extra; if (rcoNode->type <= lenNum && lenArray[rcoNode->type] > 0) { const int *typeArray = (isObj ? RCO_OBJ_EXTRA_TYPES[rcoNode-> type] : RCO_ANIM_EXTRA_TYPES[rcoNode->type]); for (j = 0, j2 = 0; (int) j < lenArray[rcoNode->type]; j++, j2++) { uint8_t cond; if (isObj) cond = (RCO_OBJ_IS_REF (rcoNode->type, j2)); else // anim cond = (RCO_ANIM_IS_REF (rcoNode->type, j2)); // cond = (RCO_ANIM_EXTRA_REFS[rcoNode->type] && j == 0); if (cond) { rRCORef *srcRef = (rRCORef *) extraPtr; RCOReference destRef; destRef.type = srcRef->type; switch (destRef.type) { case RCO_REF_EVENT: // destRef.ptr = ((char*)(srcRef->ptr)) - rco->events; destRef.ptr = srcRef->rawPtr; break; case RCO_REF_NONE: destRef.ptr = RCO_NULL_PTR; break; case RCO_REF_TEXT: destRef.ptr = srcRef->rawPtr; break; case RCO_REF_IMG: case RCO_REF_MODEL: case RCO_REF_FONT: case RCO_REF_OBJ2: case RCO_REF_ANIM: case RCO_REF_OBJ: if (srcRef->ptr) destRef.ptr = ((rRCOEntry *) (srcRef->ptr))->offset; break; default: destRef.ptr = srcRef->rawPtr; } if (rco->eSwap) { #define ENDIAN_SWAP_HALF32(x) (((x) & 0xFF) << 8 | ((x) & 0xFF00) >> 8 | ((x) & 0xFF0000) << 8 | ((x) & 0xFF000000) >> 8) destRef.type = ENDIAN_SWAP_HALF32 (destRef.type); destRef.ptr = ENDIAN_SWAP (destRef.ptr); } rco_fwrite (rcoH, &destRef, sizeof (destRef)); extraPtr += sizeof (rRCORef); j++; // if(!isObj) j2--; } else { if (rco->eSwap && typeArray[j2] != RCO_OBJ_EXTRA_TYPE_UNK) { uint32_t val = *(uint32_t *) extraPtr; val = ENDIAN_SWAP (val); rco_fwrite (rcoH, &val, sizeof (val)); } else rco_fwrite (rcoH, extraPtr, sizeof (uint32_t)); extraPtr += sizeof (uint32_t); } } } else { // TODO: think up something for unknown object types } rco_write_fix_refs (rcoNode, rcoH, rco, lenArray, lenNum, isObj); } }