xref: /netbsd-src/external/bsd/elftosb/dist/common/SourceFile.cpp (revision 993229b6fea628ff8b1fa09146c80b0cfb2768eb)
1*993229b6Sjkunz /*
2*993229b6Sjkunz  * File:	SourceFile.cpp
3*993229b6Sjkunz  *
4*993229b6Sjkunz  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5*993229b6Sjkunz  * See included license file for license details.
6*993229b6Sjkunz  */
7*993229b6Sjkunz 
8*993229b6Sjkunz #include "SourceFile.h"
9*993229b6Sjkunz #include "ELFSourceFile.h"
10*993229b6Sjkunz #include "SRecordSourceFile.h"
11*993229b6Sjkunz #include <assert.h>
12*993229b6Sjkunz #include "format_string.h"
13*993229b6Sjkunz #include "SearchPath.h"
14*993229b6Sjkunz 
15*993229b6Sjkunz using namespace elftosb;
16*993229b6Sjkunz 
17*993229b6Sjkunz //! The supported file types are currently:
18*993229b6Sjkunz //!		- ELF files
19*993229b6Sjkunz //!		- Motorola S-record files
20*993229b6Sjkunz //!		- Binary files
21*993229b6Sjkunz //!
22*993229b6Sjkunz //! Any file that is not picked up by the other subclasses will result in a
23*993229b6Sjkunz //! an instance of BinaryDataFile.
24*993229b6Sjkunz //!
25*993229b6Sjkunz //! \return An instance of the correct subclass of SourceFile for the given path.
26*993229b6Sjkunz //!
27*993229b6Sjkunz //! \exception std::runtime_error Thrown if the file cannot be opened.
28*993229b6Sjkunz //!
29*993229b6Sjkunz //! \see elftosb::ELFSourceFile
30*993229b6Sjkunz //! \see elftosb::SRecordSourceFile
31*993229b6Sjkunz //! \see elftosb::BinarySourceFile
openFile(const std::string & path)32*993229b6Sjkunz SourceFile * SourceFile::openFile(const std::string & path)
33*993229b6Sjkunz {
34*993229b6Sjkunz 	// Search for file using search paths
35*993229b6Sjkunz 	std::string actualPath;
36*993229b6Sjkunz 	bool found = PathSearcher::getGlobalSearcher().search(path, PathSearcher::kFindFile, true, actualPath);
37*993229b6Sjkunz 	if (!found)
38*993229b6Sjkunz 	{
39*993229b6Sjkunz 		throw std::runtime_error(format_string("unable to find file %s\n", path.c_str()));
40*993229b6Sjkunz 	}
41*993229b6Sjkunz 
42*993229b6Sjkunz 	std::ifstream testStream(actualPath.c_str(), std::ios_base::in | std::ios_base::binary);
43*993229b6Sjkunz 	if (!testStream.is_open())
44*993229b6Sjkunz 	{
45*993229b6Sjkunz 		throw std::runtime_error(format_string("failed to open file: %s", actualPath.c_str()));
46*993229b6Sjkunz 	}
47*993229b6Sjkunz 
48*993229b6Sjkunz 	// catch exceptions so we can close the file stream
49*993229b6Sjkunz 	try
50*993229b6Sjkunz 	{
51*993229b6Sjkunz 		if (ELFSourceFile::isELFFile(testStream))
52*993229b6Sjkunz 		{
53*993229b6Sjkunz 			testStream.close();
54*993229b6Sjkunz 			return new ELFSourceFile(actualPath);
55*993229b6Sjkunz 		}
56*993229b6Sjkunz 		else if (SRecordSourceFile::isSRecordFile(testStream))
57*993229b6Sjkunz 		{
58*993229b6Sjkunz 			testStream.close();
59*993229b6Sjkunz 			return new SRecordSourceFile(actualPath);
60*993229b6Sjkunz 		}
61*993229b6Sjkunz 
62*993229b6Sjkunz 		// treat it as a binary file
63*993229b6Sjkunz 		testStream.close();
64*993229b6Sjkunz 		return new BinarySourceFile(actualPath);
65*993229b6Sjkunz 	}
66*993229b6Sjkunz 	catch (...)
67*993229b6Sjkunz 	{
68*993229b6Sjkunz 		testStream.close();
69*993229b6Sjkunz 		throw;
70*993229b6Sjkunz 	}
71*993229b6Sjkunz }
72*993229b6Sjkunz 
SourceFile(const std::string & path)73*993229b6Sjkunz SourceFile::SourceFile(const std::string & path)
74*993229b6Sjkunz :	m_path(path), m_stream()
75*993229b6Sjkunz {
76*993229b6Sjkunz }
77*993229b6Sjkunz 
78*993229b6Sjkunz //! The file is closed if it had been left opened.
79*993229b6Sjkunz //!
~SourceFile()80*993229b6Sjkunz SourceFile::~SourceFile()
81*993229b6Sjkunz {
82*993229b6Sjkunz 	if (isOpen())
83*993229b6Sjkunz 	{
84*993229b6Sjkunz 		m_stream->close();
85*993229b6Sjkunz 	}
86*993229b6Sjkunz }
87*993229b6Sjkunz 
88*993229b6Sjkunz //! \exception std::runtime_error Raised if the file could not be opened successfully.
open()89*993229b6Sjkunz void SourceFile::open()
90*993229b6Sjkunz {
91*993229b6Sjkunz 	assert(!isOpen());
92*993229b6Sjkunz 	m_stream = new std::ifstream(m_path.c_str(), std::ios_base::in | std::ios_base::binary);
93*993229b6Sjkunz 	if (!m_stream->is_open())
94*993229b6Sjkunz 	{
95*993229b6Sjkunz 		throw std::runtime_error(format_string("failed to open file: %s", m_path.c_str()));
96*993229b6Sjkunz 	}
97*993229b6Sjkunz }
98*993229b6Sjkunz 
close()99*993229b6Sjkunz void SourceFile::close()
100*993229b6Sjkunz {
101*993229b6Sjkunz 	assert(isOpen());
102*993229b6Sjkunz 
103*993229b6Sjkunz 	m_stream->close();
104*993229b6Sjkunz 	m_stream.safe_delete();
105*993229b6Sjkunz }
106*993229b6Sjkunz 
getSize()107*993229b6Sjkunz unsigned SourceFile::getSize()
108*993229b6Sjkunz {
109*993229b6Sjkunz 	bool wasOpen = isOpen();
110*993229b6Sjkunz 	std::ifstream::pos_type oldPosition;
111*993229b6Sjkunz 
112*993229b6Sjkunz 	if (!wasOpen)
113*993229b6Sjkunz 	{
114*993229b6Sjkunz 		open();
115*993229b6Sjkunz 	}
116*993229b6Sjkunz 
117*993229b6Sjkunz 	assert(m_stream);
118*993229b6Sjkunz 	oldPosition = m_stream->tellg();
119*993229b6Sjkunz 	m_stream->seekg(0, std::ios_base::end);
120*993229b6Sjkunz 	unsigned resultSize = m_stream->tellg();
121*993229b6Sjkunz 	m_stream->seekg(oldPosition);
122*993229b6Sjkunz 
123*993229b6Sjkunz 	if (!wasOpen)
124*993229b6Sjkunz 	{
125*993229b6Sjkunz 		close();
126*993229b6Sjkunz 	}
127*993229b6Sjkunz 
128*993229b6Sjkunz 	return resultSize;
129*993229b6Sjkunz }
130*993229b6Sjkunz 
131*993229b6Sjkunz //! If the file does not support named sections, or if there is not a
132*993229b6Sjkunz //! section with the given name, this method may return NULL.
133*993229b6Sjkunz //!
134*993229b6Sjkunz //! This method is just a small wrapper that creates an
135*993229b6Sjkunz //! FixedMatcher string matcher instance and uses the createDataSource()
136*993229b6Sjkunz //! that takes a reference to a StringMatcher.
createDataSource(const std::string & section)137*993229b6Sjkunz DataSource * SourceFile::createDataSource(const std::string & section)
138*993229b6Sjkunz {
139*993229b6Sjkunz 	FixedMatcher matcher(section);
140*993229b6Sjkunz 	return createDataSource(matcher);
141*993229b6Sjkunz }
142*993229b6Sjkunz 
createDataTargetForEntryPoint()143*993229b6Sjkunz DataTarget * SourceFile::createDataTargetForEntryPoint()
144*993229b6Sjkunz {
145*993229b6Sjkunz 	if (!hasEntryPoint())
146*993229b6Sjkunz 	{
147*993229b6Sjkunz 		return NULL;
148*993229b6Sjkunz 	}
149*993229b6Sjkunz 
150*993229b6Sjkunz 	return new ConstantDataTarget(getEntryPointAddress());
151*993229b6Sjkunz }
152*993229b6Sjkunz 
createDataSource()153*993229b6Sjkunz DataSource * BinarySourceFile::createDataSource()
154*993229b6Sjkunz {
155*993229b6Sjkunz 	std::istream * fileStream = getStream();
156*993229b6Sjkunz 	assert(fileStream);
157*993229b6Sjkunz 
158*993229b6Sjkunz 	// get stream size
159*993229b6Sjkunz 	fileStream->seekg(0, std::ios_base::end);
160*993229b6Sjkunz 	int length = fileStream->tellg();
161*993229b6Sjkunz 
162*993229b6Sjkunz 	// allocate buffer
163*993229b6Sjkunz 	smart_array_ptr<uint8_t> data = new uint8_t[length];
164*993229b6Sjkunz //	if (!data)
165*993229b6Sjkunz //	{
166*993229b6Sjkunz //	    throw std::bad_alloc();
167*993229b6Sjkunz //	}
168*993229b6Sjkunz 
169*993229b6Sjkunz 	// read entire file into the buffer
170*993229b6Sjkunz 	fileStream->seekg(0, std::ios_base::beg);
171*993229b6Sjkunz 	if (fileStream->read((char *)data.get(), length).bad())
172*993229b6Sjkunz 	{
173*993229b6Sjkunz 		throw std::runtime_error(format_string("unexpected end of file: %s", m_path.c_str()));
174*993229b6Sjkunz 	}
175*993229b6Sjkunz 
176*993229b6Sjkunz 	// create the data source. the buffer is copied, so we can dispose of it.
177*993229b6Sjkunz 	return new UnmappedDataSource(data, length);
178*993229b6Sjkunz }
179