mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 18:26:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			196 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "esmwriter.hpp"
 | |
| #include <fstream>
 | |
| #include <cstring>
 | |
| 
 | |
| bool count = true;
 | |
| 
 | |
| namespace ESM
 | |
| {
 | |
| 
 | |
| int ESMWriter::getVersion()
 | |
| {
 | |
|     return m_header.version;
 | |
| }
 | |
| 
 | |
| void ESMWriter::setVersion(int ver)
 | |
| {
 | |
|     m_header.version = ver;
 | |
| }
 | |
| 
 | |
| int ESMWriter::getType()
 | |
| {
 | |
|     return m_header.type;
 | |
| }
 | |
| 
 | |
| void ESMWriter::setType(int type)
 | |
| {
 | |
|     m_header.type = type;
 | |
| }
 | |
| 
 | |
| void ESMWriter::setAuthor(const std::string& auth)
 | |
| {
 | |
|     strncpy((char*)&m_header.author, auth.c_str(), 32);
 | |
| }
 | |
| 
 | |
| void ESMWriter::setDescription(const std::string& desc)
 | |
| {
 | |
|     strncpy((char*)&m_header.desc, desc.c_str(), 256);
 | |
| }
 | |
| 
 | |
| void ESMWriter::addMaster(const std::string& name, uint64_t size)
 | |
| {
 | |
|     MasterData d;
 | |
|     d.name = name;
 | |
|     d.size = size;
 | |
|     m_masters.push_back(d);
 | |
| }
 | |
| 
 | |
| void ESMWriter::save(const std::string& file)
 | |
| {
 | |
|     std::ofstream fs(file.c_str(), std::ios_base::out | std::ios_base::trunc);
 | |
|     save(fs);
 | |
| }
 | |
| 
 | |
| void ESMWriter::save(std::ostream& file)
 | |
| {
 | |
|     m_recordCount = 0;
 | |
|     m_stream = &file;
 | |
| 
 | |
|     startRecord("TES3", 0);
 | |
| 
 | |
|     m_header.records = 0;
 | |
|     writeHNT("HEDR", m_header, 300);
 | |
|     m_headerPos = m_stream->tellp() - (std::streampos)4;
 | |
| 
 | |
|     for (std::list<MasterData>::iterator it = m_masters.begin(); it != m_masters.end(); ++it)
 | |
|     {
 | |
|         writeHNCString("MAST", it->name);
 | |
|         writeHNT("DATA", it->size);
 | |
|     }
 | |
| 
 | |
|     endRecord("TES3");
 | |
| }
 | |
| 
 | |
| void ESMWriter::close()
 | |
| {
 | |
|     std::cout << "Writing amount of saved records (" << m_recordCount - 1 << ")" << std::endl;
 | |
|     m_stream->seekp(m_headerPos);
 | |
|     writeT<int>(m_recordCount-1);
 | |
|     m_stream->seekp(0, std::ios::end);
 | |
|     m_stream->flush();
 | |
| 
 | |
|     if (!m_records.empty())
 | |
|         throw "Unclosed record remaining";
 | |
| }
 | |
| 
 | |
| void ESMWriter::startRecord(const std::string& name, uint32_t flags)
 | |
| {
 | |
|     m_recordCount++;
 | |
|     
 | |
|     writeName(name);
 | |
|     RecordData rec;
 | |
|     rec.name = name;
 | |
|     rec.position = m_stream->tellp();
 | |
|     rec.size = 0;
 | |
|     writeT<int>(0); // Size goes here
 | |
|     writeT<int>(0); // Unused header?
 | |
|     writeT(flags);
 | |
|     m_records.push_back(rec);
 | |
| 
 | |
|     assert(m_records.back().size == 0);
 | |
| }
 | |
| 
 | |
| void ESMWriter::startSubRecord(const std::string& name)
 | |
| {
 | |
|     writeName(name);
 | |
|     RecordData rec;
 | |
|     rec.name = name;
 | |
|     rec.position = m_stream->tellp();
 | |
|     rec.size = 0;
 | |
|     writeT<int>(0); // Size goes here
 | |
|     m_records.push_back(rec);
 | |
|     
 | |
|     assert(m_records.back().size == 0);
 | |
| }
 | |
| 
 | |
| void ESMWriter::endRecord(const std::string& name)
 | |
| {
 | |
|     RecordData rec = m_records.back();
 | |
|     assert(rec.name == name);
 | |
|     m_records.pop_back();
 | |
|     
 | |
|     m_stream->seekp(rec.position);
 | |
| 
 | |
|     count = false;
 | |
|     write((char*)&rec.size, sizeof(int));
 | |
|     count = true;
 | |
| 
 | |
|     m_stream->seekp(0, std::ios::end);
 | |
| 
 | |
| }
 | |
| 
 | |
| void ESMWriter::writeHNString(const std::string& name, const std::string& data)
 | |
| {
 | |
|     startSubRecord(name);
 | |
|     writeHString(data);
 | |
|     endRecord(name);
 | |
| }
 | |
| 
 | |
| void ESMWriter::writeHNString(const std::string& name, const std::string& data, int size)
 | |
| {
 | |
|     assert(static_cast<int> (data.size()) <= size);
 | |
|     startSubRecord(name);
 | |
|     writeHString(data);
 | |
| 
 | |
|     if (static_cast<int> (data.size()) < size)
 | |
|     {
 | |
|         for (int i = data.size(); i < size; ++i)
 | |
|             write("\0",1);
 | |
|     }
 | |
| 
 | |
|     endRecord(name);
 | |
| }
 | |
| 
 | |
| void ESMWriter::writeHString(const std::string& data)
 | |
| {
 | |
|     if (data.size() == 0)
 | |
|         write("\0", 1);
 | |
|     else
 | |
|     {
 | |
|         // Convert to UTF8 and return
 | |
|         std::string ascii = m_encoder->getLegacyEnc(data);
 | |
| 
 | |
|         write(ascii.c_str(), ascii.size());
 | |
|     }
 | |
| }
 | |
| 
 | |
| void ESMWriter::writeHCString(const std::string& data)
 | |
| {
 | |
|     writeHString(data);
 | |
|     if (data.size() > 0 && data[data.size()-1] != '\0')
 | |
|         write("\0", 1);
 | |
| }
 | |
| 
 | |
| void ESMWriter::writeName(const std::string& name)
 | |
| {
 | |
|     assert((name.size() == 4 && name[3] != '\0'));
 | |
|     write(name.c_str(), name.size());
 | |
| }
 | |
| 
 | |
| void ESMWriter::write(const char* data, int size)
 | |
| {
 | |
|     if (count && !m_records.empty())
 | |
|     {
 | |
|         for (std::list<RecordData>::iterator it = m_records.begin(); it != m_records.end(); ++it)
 | |
|             it->size += size;
 | |
|     }
 | |
| 
 | |
|     m_stream->write(data, size);
 | |
| }
 | |
| 
 | |
| void ESMWriter::setEncoder(ToUTF8::Utf8Encoder* encoder)
 | |
| {
 | |
|     m_encoder = encoder;
 | |
| }
 | |
| 
 | |
| }
 |