bool PsxRelocator::parseObject(ByteArray data, PsxRelocatorFile& dest) { if (memcmp(data.data(),psxObjectFileMagicNum,sizeof(psxObjectFileMagicNum)) != 0) return false; int pos = 6; std::vector<PsxSegment>& segments = dest.segments; std::vector<PsxSymbol>& syms = dest.symbols; int activeSegment = -1; int lastSegmentPartStart = -1; while (pos < data.size()) { switch (data[pos]) { case 0x10: // segment definition { PsxSegment seg; seg.id = data.getDoubleWord(pos+1); segments.push_back(seg); pos += 5; if (data[pos] != 8) return false; int nameLen = data[pos+1]; std::wstring& name = segments[segments.size()-1].name; pos += 1 + loadString(data,pos+1,name); } break; case 0x14: // group? pos += data[pos+4]+5; break; case 0x1C: // source file name pos += data[pos+3]+4; break; case 0x06: // set segment id { int id = data.getWord(pos+1); pos += 3; int num = -1; for (size_t i = 0; i < segments.size(); i++) { if (segments[i].id == id) { num = i; break; } } activeSegment = num; } break; case 0x02: // append to data segment { int size = data.getWord(pos+1); pos += 3; ByteArray d = data.mid(pos,size); pos += size; lastSegmentPartStart = segments[activeSegment].data.size(); segments[activeSegment].data.append(d); } break; case 0x08: // append zeroes data segment { int size = data.getWord(pos+1); pos += 3; ByteArray d; d.reserveBytes(size); segments[activeSegment].data.append(d); } break; case 0x0A: // relocation data { int type = data[pos+1]; pos += 2; PsxRelocation rel; rel.relativeOffset = 0; rel.filePos = pos-2; switch (type) { case 0x10: // 32 bit word rel.type = PsxRelocationType::WordLiteral; rel.segmentOffset = data.getWord(pos); pos += 2; break; case 0x4A: // jal rel.type = PsxRelocationType::FunctionCall; rel.segmentOffset = data.getWord(pos); pos += 2; break; case 0x52: // upper immerdiate rel.type = PsxRelocationType::UpperImmediate; rel.segmentOffset = data.getWord(pos); pos += 2; break; case 0x54: // lower immediate (add) rel.type = PsxRelocationType::LowerImmediate; rel.segmentOffset = data.getWord(pos); pos += 2; break; default: return false; } rel.segmentOffset += lastSegmentPartStart; checkothertype: int otherType = data[pos++]; switch (otherType) { case 0x02: // reference to symbol with id num rel.refType = PsxRelocationRefType::SymblId; rel.referenceId = data.getWord(pos); pos += 2; break; case 0x2C: // ref to other segment? rel.refType = PsxRelocationRefType::SegmentOffset; switch (data[pos++]) { case 0x00: rel.relativeOffset = data.getDoubleWord(pos); pos += 4; goto checkothertype; case 0x04: rel.referenceId = data.getWord(pos); // segment id pos += 2; if (data[pos++] != 0x00) { return false; } rel.referencePos = data.getDoubleWord(pos); pos += 4; break; default: return false; } break; case 0x2E: // negative ref? rel.refType = PsxRelocationRefType::SegmentOffset; switch (data[pos++]) { case 0x00: rel.relativeOffset = -data.getDoubleWord(pos); pos += 4; goto checkothertype; default: return false; } break; default: return false; } segments[activeSegment].relocations.push_back(rel); } break; case 0x12: // internal symbol { PsxSymbol sym; sym.type = PsxSymbolType::Internal; sym.segment = data.getWord(pos+1); sym.offset = data.getDoubleWord(pos+3); pos += 7 + loadString(data,pos+7,sym.name); syms.push_back(sym); } break; case 0x0E: // external symbol { PsxSymbol sym; sym.type = PsxSymbolType::External; sym.id = data.getWord(pos+1); pos += 3 + loadString(data,pos+3,sym.name); syms.push_back(sym); } break; case 0x30: // bss symbol? { PsxSymbol sym; sym.type = PsxSymbolType::BSS; sym.id = data.getWord(pos+1); sym.segment = data.getWord(pos+3); sym.size = data.getDoubleWord(pos+5); pos += 9 + loadString(data,pos+9,sym.name); syms.push_back(sym); } break; case 0x0C: // internal with id { PsxSymbol sym; sym.type = PsxSymbolType::InternalID; sym.id = data.getWord(pos+1); sym.segment = data.getWord(pos+3); sym.offset = data.getDoubleWord(pos+5); pos += 9 + loadString(data,pos+9,sym.name); syms.push_back(sym); } break; case 0x4A: // function { PsxSymbol sym; sym.type = PsxSymbolType::Function; sym.segment = data.getWord(pos+1); sym.offset = data.getDoubleWord(pos+3); pos += 0x1D + loadString(data,pos+0x1D,sym.name); syms.push_back(sym); } break; case 0x4C: // function size pos += 11; break; case 0x3C: // ?? pos += 3; break; case 0x00: // ?? pos++; break; case 0x32: // ?? pos += 3; break; case 0x3A: // ?? pos += 9; break; default: return false; } } return true; }