diff --git a/Commands/CDirectiveFile.cpp b/Commands/CDirectiveFile.cpp index 7df4ac61..4ab6d41c 100644 --- a/Commands/CDirectiveFile.cpp +++ b/Commands/CDirectiveFile.cpp @@ -562,3 +562,162 @@ void DirectiveObjImport::writeSymData(SymbolData& symData) const rel.writeSymbols(symData); } + +// +// CDirectiveSymImport +// +std::string trimSymFileLine(std::string line) +{ + // Trim start of line + size_t lineStart = line.find_first_not_of(" \t"); + + // End line at comment (starting with ;) + // \x1A included here as well since No$gba .sym file ends with it + size_t lineEnd = line.find_first_of(";\x1A"); + + if (lineStart >= lineEnd) + return std::string(); // line consists of only whitespace + + // Trim end of line + lineEnd = line.find_last_not_of(" \t",lineEnd-1); + // lineEnd now points to position of last char + return line.substr(lineStart,lineEnd-lineStart+1); +} + +CDirectiveSymImport::CDirectiveSymImport(const fs::path& fileName) +{ + // We may be adding global labels, so start a new section + updateSection(++Global.Section); + + this->fileName = getFullPathName(fileName); + if (!fs::exists(this->fileName)) + { + Logger::printError(Logger::FatalError,"File %s not found",this->fileName.u8string()); + return; + } + + TextFile file; + file.open(this->fileName,TextFile::Read); + if (!file.isOpen()) + { + Logger::printError(Logger::FatalError,"Could not open file %s",this->fileName.u8string()); + return; + } + + std::vector lines = file.readAll(); + size_t l = 0; + for (std::string line: lines) + { + l++; + line = trimSymFileLine(line); + if (line.empty()) + continue; + + // Parse symbol address + const char* addrStart = (char*)line.c_str(); + char* addrEnd; + uint32_t symAddr = strtoul(addrStart,&addrEnd,16); + // Check: not 8 chars, not followed by space/tab + if (addrStart+8 != addrEnd || !strchr(" \t",*addrEnd)) + { + Logger::printError(Logger::Warning,"Invalid symbol address on line %i of symbols file %s",l,this->fileName); + continue; + } + + // Rest of the line is the symbol value + std::string symVal = std::string(addrEnd); + symVal = symVal.substr(symVal.find_first_not_of(" \t")); + + std::string name = symVal; + + // Get optional label size + size_t commaPos = symVal.find(','); + uint32_t funcSize = 0; + if (commaPos != std::string::npos) + { + // Parse size + const char* sizeStart = symVal.c_str()+commaPos+1; + char* sizeEnd; + funcSize = strtoul(sizeStart,&sizeEnd,16); + // Check: empty size, not in range, not followed by eol/space/tab/comma + if (sizeStart == sizeEnd || errno == ERANGE || !strchr("\0 \t,",*sizeEnd)) + { + Logger::printError(Logger::Warning,"Invalid function size on line %i of symbols file %s",l,this->fileName); + funcSize = 0; + // We can still salvage this I guess + } + else { + // Got valid label size, so remove it from identifier (trim end in the process) + name = symVal.substr(0,symVal.find_first_of(" \t")); + } + } + + // Create label for this symbol, if it's not a directive and it would be a global label + const Identifier identifier = Identifier(name); + if (name.find('.') != 0 && Global.symbolTable.isGlobalSymbol(identifier)) + { + std::shared_ptr