Skip to content

Instantly share code, notes, and snippets.

@codestation
Last active August 29, 2015 14:08
Show Gist options
  • Save codestation/eb6291e543473e9a9fa6 to your computer and use it in GitHub Desktop.
Save codestation/eb6291e543473e9a9fa6 to your computer and use it in GitHub Desktop.
// Copyright (c) 2014 codestation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <cinttypes>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
struct lmd_header
{
char lmd_name[4]; // lmd\0
uint32_t version; // 1.1.12
uint32_t unk1_entries;
uint32_t ascii_table_size;
uint32_t string_index_entries;
uint32_t unk1_offset;
uint32_t ascii_table_offset;
uint32_t string_index_offset; // at 0x1C
uint32_t file_size; // minus name at end of file
} __attribute__((packed));
struct unk1_entry
{
uint32_t hash; // ?
uint32_t unk; // always 0x400000
} __attribute__((packed));
struct string_index_entry
{
uint32_t string_offset;
uint32_t characters;
uint32_t size_char; // same as characters
} __attribute__((packed));
int main(int argc, char **argv)
{
if(argc < 2)
{
std::cerr << "Usage: " << argv[0] << " <lmd_file>" << std::endl;
return 1;
}
std::string lmd_filename {argv[1]};
std::fstream lmd;
lmd.open(lmd_filename, std::fstream::in | std::fstream::binary);
lmd_header header;
lmd.read(reinterpret_cast<char *>(&header), sizeof(lmd_header));
if(std::string{header.lmd_name} != "lmd")
{
std::cerr << "Not a lmd file" << std::endl;
return 1;
}
std::cout << "lmd version: 0x" << std::setfill('0') << std::setw(8) << std::hex << header.version << std::endl;
std::cout << "unk table offset: 0x" << header.unk1_offset << std::endl;
std::cout << "unk table entries: " << std::dec << header.unk1_entries << std::endl;
std::cout << "ascii table offset: 0x" << std::setfill('0') << std::setw(8) << std::hex << header.ascii_table_offset << std::endl;
std::cout << "ascii table size: " << std::dec << header.ascii_table_size << std::endl;
std::cout << "string index offset: 0x" << std::setfill('0') << std::setw(8) << std::hex << header.string_index_offset << std::endl;
std::cout << "string index entries: " << std::dec << header.string_index_entries << std::endl;
string_index_entry entry;
std::cout << "\nstring table entries:\n" << std::endl;
std::basic_ofstream<char> out(lmd_filename + "_out.txt", std::ofstream::binary | std::ofstream::trunc);
if(!out)
{
std::cout << "cannot create output file " << lmd_filename + "_out.txt" << std::endl;
return 1;
}
static const unsigned char bom[2] {0xff, 0xfe};
out.write(reinterpret_cast<const char *>(bom), 2);
for(int i = 0; i < header.string_index_entries; ++i)
{
lmd.seekg(header.string_index_offset + i * sizeof(string_index_entry));
lmd.read(reinterpret_cast<char *>(&entry), sizeof(string_index_entry));
std::cout << "string #" << std::dec << std::setfill('0') << std::setw(5) << i
<< " at offset 0x" << std::hex << std::setfill('0') << std::setw(8) << entry.string_offset
<< ", characters: " << std::dec << entry.characters << std::endl;
lmd.seekg(entry.string_offset);
std::vector<char> buffer(entry.characters * 2);
lmd.read(buffer.data(), buffer.size());
static const char marker[4] {'#', 0, ' ', 0};
out.write(marker, 4);
out.write(buffer.data(), entry.characters * 2);
static const char newline[4] {'\r', 0, '\n', 0x0};
out.write(newline, 4);
}
lmd.seekg(header.file_size);
std::string name;
lmd >> name;
std::cout << "Internal file name: " << name << std::endl;
std::cout << "\nCreated output file: " << lmd_filename + "_out.txt" << std::endl;
out.close();
lmd.close();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment