//===- InputBuilder.cpp ---------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/MC/InputBuilder.h>
#include <mcld/LinkerConfig.h>
#include <mcld/Config/Config.h>
#include <mcld/Support/Path.h>
#include <mcld/MC/InputFactory.h>
#include <mcld/MC/ContextFactory.h>
#include <mcld/Support/MemoryAreaFactory.h>
using namespace mcld;
InputBuilder::InputBuilder(const LinkerConfig& pConfig)
: m_Config(pConfig),
m_pCurrentTree(NULL), m_pMove(NULL), m_Root(),
m_bOwnFactory(true) {
m_pInputFactory = new InputFactory(MCLD_NUM_OF_INPUTS, pConfig);
m_pContextFactory = new ContextFactory(MCLD_NUM_OF_INPUTS);
m_pMemFactory = new MemoryAreaFactory(MCLD_NUM_OF_INPUTS);
}
InputBuilder::InputBuilder(const LinkerConfig& pConfig,
InputFactory& pInputFactory,
ContextFactory& pContextFactory,
MemoryAreaFactory& pMemoryFactory,
bool pDelegate)
: m_Config(pConfig),
m_pInputFactory(&pInputFactory),
m_pMemFactory(&pMemoryFactory),
m_pContextFactory(&pContextFactory),
m_pCurrentTree(NULL), m_pMove(NULL), m_Root(),
m_bOwnFactory(pDelegate) {
}
InputBuilder::~InputBuilder()
{
if (m_bOwnFactory) {
delete m_pInputFactory;
delete m_pContextFactory;
delete m_pMemFactory;
}
}
Input* InputBuilder::createInput(const std::string& pName,
const sys::fs::Path& pPath,
unsigned int pType,
off_t pFileOffset)
{
return m_pInputFactory->produce(pName, pPath, pType, pFileOffset);
}
InputTree& InputBuilder::enterGroup()
{
assert(NULL != m_pCurrentTree && NULL != m_pMove);
m_pCurrentTree->enterGroup(m_Root, *m_pMove);
m_pMove->move(m_Root);
m_ReturnStack.push(m_Root);
m_pMove = &InputTree::Downward;
return *m_pCurrentTree;
}
InputTree& InputBuilder::exitGroup()
{
assert(NULL != m_pCurrentTree && NULL != m_pMove);
m_Root = m_ReturnStack.top();
m_ReturnStack.pop();
m_pMove = &InputTree::Afterward;
return *m_pCurrentTree;
}
bool InputBuilder::isInGroup() const
{
return !m_ReturnStack.empty();
}
const InputTree& InputBuilder::getCurrentTree() const
{
assert(NULL != m_pCurrentTree && NULL != m_pMove);
return *m_pCurrentTree;
}
InputTree& InputBuilder::getCurrentTree()
{
assert(NULL != m_pCurrentTree && NULL != m_pMove);
return *m_pCurrentTree;
}
void InputBuilder::setCurrentTree(InputTree& pInputTree)
{
m_pCurrentTree = &pInputTree;
m_Root = m_pCurrentTree->root();
m_pMove = &InputTree::Downward;
}
bool InputBuilder::setContext(Input& pInput, bool pCheck)
{
// The object files in an archive have common path. Every object files in an
// archive needs a individual context. We identify the object files in an
// archive by its file offset. Their file offsets are not zero.
LDContext* context = NULL;
if (0 != pInput.fileOffset() || !pCheck) {
// pInput is an object in an archive file. Produce a new context in this
// case.
context = m_pContextFactory->produce();
}
else {
// Using pInput.path() to avoid from creating context for identical file
// twice.
context = m_pContextFactory->produce(pInput.path());
}
pInput.setContext(context);
return true;
}
bool InputBuilder::setMemory(Input& pInput,
FileHandle::OpenMode pMode,
FileHandle::Permission pPerm)
{
MemoryArea *memory = m_pMemFactory->produce(pInput.path(), pMode, pPerm);
if (!memory->handler()->isGood())
return false;
pInput.setMemArea(memory);
return true;
}
bool InputBuilder::setMemory(Input& pInput, void* pMemBuffer, size_t pSize)
{
MemoryArea *memory = m_pMemFactory->produce(pMemBuffer, pSize);
pInput.setMemArea(memory);
return true;
}
const AttrConstraint& InputBuilder::getConstraint() const
{
return m_Config.attribute().constraint();
}
const AttributeProxy& InputBuilder::getAttributes() const
{
return m_pInputFactory->attr();
}
AttributeProxy& InputBuilder::getAttributes()
{
return m_pInputFactory->attr();
}