/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
* 
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <string.h>

#include "elfsectionmanager.h"

void ElfSectionManager::GetFileFragmentData(FileFragmentData & aFileFragmentData ){
	int nSections = iSections.size();
	if (nSections > 0){
		iData = new Elf32_Shdr[nSections];
		Elf32_Shdr * p = iData;
		SectionList::iterator aSection = iSections.begin();
		SectionList::iterator end = iSections.end();
		while (aSection != end) {
			*p = aSection->GetSectionHeader().iElf32Shdr;
			p++;
			aSection++;
		}
		SetFileFragmentData(aFileFragmentData, Size(), reinterpret_cast<char *>(iData));
	}
}

size_t ElfSectionManager::Size(){
	return SectionHeaderSize();
}

void ElfSectionManager::DeleteFileFragmentData(){
	if (iData) {
		Elf32_Shdr * d = iData;
		iData = NULL;
		delete[] d;
	}
}

void ElfSectionManager::AddData(){
	AddData(iOutputFile);
}

void ElfSectionManager::AddData(OutputFile & aOutputFile){
	if (iSections.size() > 0) {
		SectionList::iterator aSection = iSections.begin();
		SectionList::iterator end = iSections.end();
		while (aSection != end) {
			aSection->AddData(aOutputFile);
			aSection++;
		}
		AddSectionTable();
	}
}

void ElfSectionManager::EnsureSectionStringTableSectionAdded(){
	if (iSectionStringTableSectionAdded) return;
	
	// set iSectionStringTableSectionAdded true now so we don't do the next bit twice;
	iSectionStringTableSectionAdded = true;

	// first create the UNDEF section
	ElfSectionNoData * aUndefData = new ElfSectionNoData();
	
	Elf32_Shdr undef;
	undef.sh_name = 0; 
	undef.sh_type = SHT_NULL;
	undef.sh_flags = 0;
	undef.sh_addr = 0;
	undef.sh_offset = 0; 
	undef.sh_size = 0; 
	undef.sh_link = 0;
	undef.sh_info = 0;
	undef.sh_addralign = 0;
	undef.sh_entsize = 0;
	
	ElfSection aUndefSection(aUndefData, "", undef);
	AddSection(aUndefSection);
	
	ElfSectionElfData * aSectionStringTableSectionData = new ElfSectionElfData(iStringTable);
	Elf32_Shdr shdr;
	shdr.sh_name = 0; // for now.
	shdr.sh_type = SHT_STRTAB;
	shdr.sh_flags = 0;
	shdr.sh_addr = 0;
	shdr.sh_offset = 0; // for now
	shdr.sh_size = 0; // for now.
	shdr.sh_link = SHN_UNDEF;
	shdr.sh_info = 0;
	shdr.sh_addralign = 0;
	shdr.sh_entsize = 0;

	ElfSection aSectionStringTableSection(aSectionStringTableSectionData, ".shstrtab", shdr);
	AddSection(aSectionStringTableSection);
	iElf32Header.SetSectionStringNdx(iSections.size() - 1);
}
void ElfSectionManager::AddSection(ElfSection & aSection){
	EnsureSectionStringTableSectionAdded();
	if (aSection.GetName().size() > 0){
		// rename sections for GDB (yuk!)
		String sectionName(aSection.GetName());
		String ro("ER_RO");
		String text(".text");
		if (sectionName == ro){
			sectionName = text;
		} else {
			String rw("ER_RW");
			String data(".data");
			if (sectionName == rw){
				sectionName = data;
			} else {
				String zi("ER_ZI");
				String bss(".bss");
				if (sectionName == zi)
					sectionName = bss;
			}
		}
		size_t nameOffset = iStringTable.AddName(sectionName);
		aSection.SetNameOffset(nameOffset);
	} else {
		// use the initial Null String.
		size_t nameOffset = iStringTable.AllocateInitialNullString();
		aSection.SetNameOffset(nameOffset);
	}
	aSection.SetIndex(iSections.size());
	iSections.push_back(aSection);
	iElf32Header.AddSectionHdr();
}
	
size_t ElfSectionManager::SectionHeaderSize(){
	return iSections.size() * sizeof(Elf32_Shdr);
}

void ElfSectionManager::AddSectionStringTable(){
	// Assume the section header already setup and we've got hold of it. We need to say where the strings ended up.
	const FileFragment & aSectionTableFrag = iOutputFile.GetFileFragment(this);	
	SetOffset(aSectionTableFrag.GetOffset());
}

void ElfSectionManager::AddSectionTable(){
	const FileFragment & aSectionTableFrag = iOutputFile.GetFileFragment(this);	
	SetOffset(aSectionTableFrag.GetOffset());
	iElf32Header.SetSectionHdrOffset(GetOffset());
}
