mirror of
https://github.com/SAT-R/sa2.git
synced 2026-10-28 09:43:38 +00:00
migrate to new scaninc, remove unused deps, fix make tidy
This commit is contained in:
1 parent
e831653f1a
commit
55a73a6e6d
39 files changed
+343
-27013
No files matched your search
Vendored
-1
@@ -1 +0,0 @@
|
||||
bin2c
|
||||
Vendored
-19
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2016 YamaArashi
|
||||
|
||||
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.
|
||||
Vendored
-16
@@ -1,16 +0,0 @@
|
||||
CC = gcc
|
||||
|
||||
CFLAGS = -Wall -Wextra -Werror -std=c11 -O2 -s
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
SRCS = bin2c.c
|
||||
|
||||
all: bin2c
|
||||
@:
|
||||
|
||||
bin2c: $(SRCS)
|
||||
$(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
$(RM) bin2c bin2c.exe
|
||||
Vendored
-201
@@ -1,201 +0,0 @@
|
||||
// Copyright(c) 2015-2016 YamaArashi
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define FATAL_ERROR(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
fprintf(stderr, format, __VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define FATAL_ERROR(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
fprintf(stderr, format, ##__VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
unsigned char *ReadWholeFile(char *path, int *size)
|
||||
{
|
||||
FILE *fp = fopen(path, "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
|
||||
*size = ftell(fp);
|
||||
|
||||
unsigned char *buffer = malloc(*size);
|
||||
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
|
||||
|
||||
rewind(fp);
|
||||
|
||||
if (fread(buffer, *size, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read \"%s\".\n", path);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int ExtractData(unsigned char *buffer, int offset, int size)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
return buffer[offset];
|
||||
case 2:
|
||||
return (buffer[offset + 1] << 8)
|
||||
| buffer[offset];
|
||||
case 4:
|
||||
return (buffer[offset + 3] << 24)
|
||||
| (buffer[offset + 2] << 16)
|
||||
| (buffer[offset + 1] << 8)
|
||||
| buffer[offset];
|
||||
default:
|
||||
FATAL_ERROR("Invalid size passed to ExtractData.\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3)
|
||||
FATAL_ERROR("Usage: bin2c INPUT_FILE VAR_NAME [OPTIONS...]\n");
|
||||
|
||||
int fileSize;
|
||||
unsigned char *buffer = ReadWholeFile(argv[1], &fileSize);
|
||||
char *var_name = argv[2];
|
||||
int col = 1;
|
||||
int pad = 0;
|
||||
int size = 1;
|
||||
bool isSigned = false;
|
||||
bool isStatic = false;
|
||||
bool isDecimal = false;
|
||||
|
||||
for (int i = 3; i < argc; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "-col"))
|
||||
{
|
||||
i++;
|
||||
|
||||
if (i >= argc)
|
||||
FATAL_ERROR("Missing argument after '-col'.\n");
|
||||
|
||||
col = atoi(argv[i]);
|
||||
}
|
||||
else if (!strcmp(argv[i], "-pad"))
|
||||
{
|
||||
i++;
|
||||
|
||||
if (i >= argc)
|
||||
FATAL_ERROR("Missing argument after '-pad'.\n");
|
||||
|
||||
pad = atoi(argv[i]);
|
||||
}
|
||||
else if (!strcmp(argv[i], "-size"))
|
||||
{
|
||||
i++;
|
||||
|
||||
if (i >= argc)
|
||||
FATAL_ERROR("Missing argument after '-size'.\n");
|
||||
|
||||
size = atoi(argv[i]);
|
||||
|
||||
if (size != 1 && size != 2 && size != 4)
|
||||
FATAL_ERROR("Size must be 1, 2, or 4.\n");
|
||||
}
|
||||
else if (!strcmp(argv[i], "-signed"))
|
||||
{
|
||||
isSigned = true;
|
||||
isDecimal = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-static"))
|
||||
{
|
||||
isStatic = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-decimal"))
|
||||
{
|
||||
isDecimal = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
FATAL_ERROR("Unrecognized option '%s'.\n", argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((fileSize & (size - 1)) != 0)
|
||||
FATAL_ERROR("Size %d doesn't evenly divide file size %d.\n", size, fileSize);
|
||||
|
||||
printf("// Generated file. Do not edit.\n\n");
|
||||
|
||||
if (isStatic)
|
||||
printf("static ");
|
||||
|
||||
printf("const ");
|
||||
|
||||
if (isSigned)
|
||||
printf("s%d ", 8 * size);
|
||||
else
|
||||
printf("u%d ", 8 * size);
|
||||
|
||||
printf("%s[] =\n{", var_name);
|
||||
|
||||
int count = fileSize / size;
|
||||
int offset = 0;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (i % col == 0)
|
||||
printf("\n ");
|
||||
|
||||
int data = ExtractData(buffer, offset, size);
|
||||
offset += size;
|
||||
|
||||
if (isDecimal)
|
||||
{
|
||||
if (isSigned)
|
||||
printf("%*d, ", pad, data);
|
||||
else
|
||||
printf("%*uu, ", pad, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%#*xu, ", pad, data);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n};\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
jsonproc
|
||||
Vendored
-20
@@ -1,20 +0,0 @@
|
||||
CXX := g++
|
||||
|
||||
CXXFLAGS := -Wall -std=c++11 -O2
|
||||
|
||||
INCLUDES := -I .
|
||||
|
||||
SRCS := jsonproc.cpp
|
||||
|
||||
HEADERS := jsonproc.h inja.hpp nlohmann/json.hpp
|
||||
|
||||
.PHONY: clean all
|
||||
|
||||
all: jsonproc
|
||||
@:
|
||||
|
||||
jsonproc: $(SRCS) $(HEADERS)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) $(SRCS) -o $@ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
$(RM) jsonproc jsonproc.exe
|
||||
Vendored
-3529
File diff suppressed because it is too large.
Load diff
Vendored
-116
@@ -1,116 +0,0 @@
|
||||
// jsonproc.cpp
|
||||
|
||||
#include "jsonproc.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <string>
|
||||
using std::string; using std::to_string;
|
||||
|
||||
#include <inja.hpp>
|
||||
using namespace inja;
|
||||
using json = nlohmann::json;
|
||||
|
||||
std::map<string, string> customVars;
|
||||
|
||||
void set_custom_var(string key, string value)
|
||||
{
|
||||
customVars[key] = value;
|
||||
}
|
||||
|
||||
string get_custom_var(string key)
|
||||
{
|
||||
return customVars[key];
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 4)
|
||||
FATAL_ERROR("USAGE: jsonproc <json-filepath> <template-filepath> <output-filepath>\n");
|
||||
|
||||
string jsonfilepath = argv[1];
|
||||
string templateFilepath = argv[2];
|
||||
string outputFilepath = argv[3];
|
||||
|
||||
Environment env;
|
||||
|
||||
// Add custom command callbacks.
|
||||
env.add_callback("doNotModifyHeader", 0, [jsonfilepath, templateFilepath](Arguments& args) {
|
||||
return "//\n// DO NOT MODIFY THIS FILE! It is auto-generated from " + jsonfilepath +" and Inja template " + templateFilepath + "\n//\n";
|
||||
});
|
||||
|
||||
env.add_callback("contains", 2, [](Arguments& args) {
|
||||
string word = args.at(0)->get<string>();
|
||||
string check = args.at(1)->get<string>();
|
||||
|
||||
return word.find(check) != std::string::npos;
|
||||
});
|
||||
|
||||
env.add_callback("subtract", 2, [](Arguments& args) {
|
||||
int minuend = args.at(0)->get<int>();
|
||||
int subtrahend = args.at(1)->get<int>();
|
||||
|
||||
return minuend - subtrahend;
|
||||
});
|
||||
|
||||
env.add_callback("setVar", 2, [=](Arguments& args) {
|
||||
string key = args.at(0)->get<string>();
|
||||
string value = args.at(1)->get<string>();
|
||||
set_custom_var(key, value);
|
||||
return "";
|
||||
});
|
||||
|
||||
env.add_callback("setVarInt", 2, [=](Arguments& args) {
|
||||
string key = args.at(0)->get<string>();
|
||||
string value = to_string(args.at(1)->get<int>());
|
||||
set_custom_var(key, value);
|
||||
return "";
|
||||
});
|
||||
|
||||
env.add_callback("getVar", 1, [=](Arguments& args) {
|
||||
string key = args.at(0)->get<string>();
|
||||
return get_custom_var(key);
|
||||
});
|
||||
|
||||
env.add_callback("concat", 2, [](Arguments& args) {
|
||||
string first = args.at(0)->get<string>();
|
||||
string second = args.at(1)->get<string>();
|
||||
return first + second;
|
||||
});
|
||||
|
||||
env.add_callback("removePrefix", 2, [](Arguments& args) {
|
||||
string rawValue = args.at(0)->get<string>();
|
||||
string prefix = args.at(1)->get<string>();
|
||||
string::size_type i = rawValue.find(prefix);
|
||||
if (i != 0)
|
||||
return rawValue;
|
||||
|
||||
return rawValue.erase(0, prefix.length());
|
||||
});
|
||||
|
||||
env.add_callback("removeSuffix", 2, [](Arguments& args) {
|
||||
string rawValue = args.at(0)->get<string>();
|
||||
string suffix = args.at(1)->get<string>();
|
||||
string::size_type i = rawValue.rfind(suffix);
|
||||
if (i == string::npos)
|
||||
return rawValue;
|
||||
|
||||
return rawValue.substr(0, i);
|
||||
});
|
||||
|
||||
// single argument is a json object
|
||||
env.add_callback("isEmpty", 1, [](Arguments& args) {
|
||||
return args.at(0)->empty();
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
env.write_with_json_file(templateFilepath, jsonfilepath, outputFilepath);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
FATAL_ERROR("JSONPROC_ERROR: %s\n", e.what());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Vendored
-32
@@ -1,32 +0,0 @@
|
||||
// jsonproc.h
|
||||
|
||||
#ifndef JSONPROC_H
|
||||
#define JSONPROC_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
using std::fprintf; using std::exit;
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define FATAL_ERROR(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
fprintf(stderr, format, __VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define FATAL_ERROR(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
fprintf(stderr, format, ##__VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // JSONPROC_H
|
||||
Vendored
-20842
File diff suppressed because it is too large.
Load diff
Vendored
-1
@@ -1 +0,0 @@
|
||||
ramscrgen
|
||||
Vendored
-19
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2016 YamaArashi
|
||||
|
||||
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.
|
||||
Vendored
-18
@@ -1,18 +0,0 @@
|
||||
CXX := g++
|
||||
|
||||
CXXFLAGS := -std=c++11 -O2 -s -Wall -Wno-switch -Werror
|
||||
|
||||
SRCS := main.cpp sym_file.cpp elf.cpp
|
||||
|
||||
HEADERS := ramscrgen.h sym_file.h elf.h char_util.h
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: ramscrgen
|
||||
@:
|
||||
|
||||
ramscrgen: $(SRCS) $(HEADERS)
|
||||
$(CXX) $(CXXFLAGS) $(SRCS) -o $@ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
$(RM) ramscrgen ramscrgen.exe
|
||||
Vendored
-71
@@ -1,71 +0,0 @@
|
||||
// Copyright(c) 2016 YamaArashi
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef CHAR_UTIL_H
|
||||
#define CHAR_UTIL_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
inline bool IsAscii(unsigned char c)
|
||||
{
|
||||
return (c < 128);
|
||||
}
|
||||
|
||||
inline bool IsAsciiAlpha(unsigned char c)
|
||||
{
|
||||
return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
|
||||
}
|
||||
|
||||
inline bool IsAsciiDigit(unsigned char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
inline bool IsAsciiHexDigit(unsigned char c)
|
||||
{
|
||||
return ((c >= '0' && c <= '9')
|
||||
|| (c >= 'a' && c <= 'f')
|
||||
|| (c >= 'A' && c <= 'F'));
|
||||
}
|
||||
|
||||
inline bool IsAsciiAlphanum(unsigned char c)
|
||||
{
|
||||
return (IsAsciiAlpha(c) || IsAsciiDigit(c));
|
||||
}
|
||||
|
||||
inline bool IsAsciiPrintable(unsigned char c)
|
||||
{
|
||||
return (c >= ' ' && c <= '~');
|
||||
}
|
||||
|
||||
// Returns whether the character can start the identifier of a "{FOO}" constant in strings.
|
||||
inline bool IsIdentifierStartingChar(unsigned char c)
|
||||
{
|
||||
return IsAsciiAlpha(c) || c == '_';
|
||||
}
|
||||
|
||||
// Returns whether the character can be used in the identifier of a "{FOO}" constant in strings.
|
||||
inline bool IsIdentifierChar(unsigned char c)
|
||||
{
|
||||
return IsAsciiAlphanum(c) || c == '_';
|
||||
}
|
||||
|
||||
#endif // CHAR_UTIL_H
|
||||
Vendored
-195
@@ -1,195 +0,0 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "ramscrgen.h"
|
||||
#include "elf.h"
|
||||
|
||||
#define SHN_COMMON 0xFFF2
|
||||
|
||||
static std::string s_elfPath;
|
||||
|
||||
static FILE *s_file;
|
||||
|
||||
static std::uint32_t s_sectionHeaderOffset;
|
||||
static int s_sectionHeaderEntrySize;
|
||||
static int s_sectionCount;
|
||||
static int s_shstrtabIndex;
|
||||
|
||||
static std::uint32_t s_symtabOffset;
|
||||
static std::uint32_t s_strtabOffset;
|
||||
|
||||
static std::uint32_t s_symbolCount;
|
||||
|
||||
struct Symbol
|
||||
{
|
||||
std::uint32_t nameOffset;
|
||||
std::uint32_t size;
|
||||
};
|
||||
|
||||
static void Seek(long offset)
|
||||
{
|
||||
if (std::fseek(s_file, offset, SEEK_SET) != 0)
|
||||
FATAL_ERROR("error: failed to seek to %ld in \"%s\"", offset, s_elfPath.c_str());
|
||||
}
|
||||
|
||||
static void Skip(long offset)
|
||||
{
|
||||
if (std::fseek(s_file, offset, SEEK_CUR) != 0)
|
||||
FATAL_ERROR("error: failed to skip %ld bytes in \"%s\"", offset, s_elfPath.c_str());
|
||||
}
|
||||
|
||||
static std::uint32_t ReadInt8()
|
||||
{
|
||||
int c = std::fgetc(s_file);
|
||||
|
||||
if (c < 0)
|
||||
FATAL_ERROR("error: unexpected EOF when reading ELF file \"%s\"\n", s_elfPath.c_str());
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static std::uint32_t ReadInt16()
|
||||
{
|
||||
std::uint32_t val = 0;
|
||||
val |= ReadInt8();
|
||||
val |= ReadInt8() << 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
static std::uint32_t ReadInt32()
|
||||
{
|
||||
std::uint32_t val = 0;
|
||||
val |= ReadInt8();
|
||||
val |= ReadInt8() << 8;
|
||||
val |= ReadInt8() << 16;
|
||||
val |= ReadInt8() << 24;
|
||||
return val;
|
||||
}
|
||||
|
||||
static std::string ReadString()
|
||||
{
|
||||
std::string s;
|
||||
char c;
|
||||
|
||||
while ((c = ReadInt8()) != 0)
|
||||
s += c;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void VerifyElfIdent()
|
||||
{
|
||||
char expectedMagic[4] = { 0x7F, 'E', 'L', 'F' };
|
||||
char magic[4];
|
||||
|
||||
if (std::fread(magic, 4, 1, s_file) != 1)
|
||||
FATAL_ERROR("error: failed to read ELF magic from \"%s\"\n", s_elfPath.c_str());
|
||||
|
||||
if (std::memcmp(magic, expectedMagic, 4) != 0)
|
||||
FATAL_ERROR("error: ELF magic did not match in \"%s\"\n", s_elfPath.c_str());
|
||||
|
||||
if (std::fgetc(s_file) != 1)
|
||||
FATAL_ERROR("error: \"%s\" not 32-bit ELF\n", s_elfPath.c_str());
|
||||
|
||||
if (std::fgetc(s_file) != 1)
|
||||
FATAL_ERROR("error: \"%s\" not little-endian ELF\n", s_elfPath.c_str());
|
||||
}
|
||||
|
||||
static void ReadElfHeader()
|
||||
{
|
||||
Seek(0x20);
|
||||
s_sectionHeaderOffset = ReadInt32();
|
||||
Seek(0x2E);
|
||||
s_sectionHeaderEntrySize = ReadInt16();
|
||||
s_sectionCount = ReadInt16();
|
||||
s_shstrtabIndex = ReadInt16();
|
||||
}
|
||||
|
||||
static std::string GetSectionName(std::uint32_t shstrtabOffset, int index)
|
||||
{
|
||||
Seek(s_sectionHeaderOffset + s_sectionHeaderEntrySize * index);
|
||||
std::uint32_t nameOffset = ReadInt32();
|
||||
Seek(shstrtabOffset + nameOffset);
|
||||
return ReadString();
|
||||
}
|
||||
|
||||
static void FindTableOffsets()
|
||||
{
|
||||
s_symtabOffset = 0;
|
||||
s_strtabOffset = 0;
|
||||
|
||||
Seek(s_sectionHeaderOffset + s_sectionHeaderEntrySize * s_shstrtabIndex + 0x10);
|
||||
std::uint32_t shstrtabOffset = ReadInt32();
|
||||
|
||||
for (int i = 0; i < s_sectionCount; i++)
|
||||
{
|
||||
std::string name = GetSectionName(shstrtabOffset, i);
|
||||
|
||||
if (name == ".symtab")
|
||||
{
|
||||
if (s_symtabOffset)
|
||||
FATAL_ERROR("error: mutiple .symtab sections found in \"%s\"\n", s_elfPath.c_str());
|
||||
Seek(s_sectionHeaderOffset + s_sectionHeaderEntrySize * i + 0x10);
|
||||
s_symtabOffset = ReadInt32();
|
||||
std::uint32_t size = ReadInt32();
|
||||
s_symbolCount = size / 16;
|
||||
}
|
||||
else if (name == ".strtab")
|
||||
{
|
||||
if (s_strtabOffset)
|
||||
FATAL_ERROR("error: mutiple .strtab sections found in \"%s\"\n", s_elfPath.c_str());
|
||||
Seek(s_sectionHeaderOffset + s_sectionHeaderEntrySize * i + 0x10);
|
||||
s_strtabOffset = ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
if (!s_symtabOffset)
|
||||
FATAL_ERROR("error: couldn't find .symtab section in \"%s\"\n", s_elfPath.c_str());
|
||||
|
||||
if (!s_strtabOffset)
|
||||
FATAL_ERROR("error: couldn't find .strtab section in \"%s\"\n", s_elfPath.c_str());
|
||||
}
|
||||
|
||||
std::map<std::string, std::uint32_t> GetCommonSymbols(std::string path)
|
||||
{
|
||||
s_elfPath = path;
|
||||
|
||||
std::map<std::string, std::uint32_t> commonSymbols;
|
||||
|
||||
s_file = std::fopen(s_elfPath.c_str(), "rb");
|
||||
|
||||
if (s_file == NULL)
|
||||
FATAL_ERROR("error: failed to open \"%s\" for reading\n", path.c_str());
|
||||
|
||||
VerifyElfIdent();
|
||||
ReadElfHeader();
|
||||
FindTableOffsets();
|
||||
|
||||
std::vector<Symbol> commonSymbolVec;
|
||||
|
||||
Seek(s_symtabOffset);
|
||||
|
||||
for (std::uint32_t i = 0; i < s_symbolCount; i++)
|
||||
{
|
||||
Symbol sym;
|
||||
sym.nameOffset = ReadInt32();
|
||||
Skip(4);
|
||||
sym.size = ReadInt32();
|
||||
Skip(2);
|
||||
std::uint16_t sectionIndex = ReadInt16();
|
||||
if (sectionIndex == SHN_COMMON)
|
||||
commonSymbolVec.push_back(sym);
|
||||
}
|
||||
|
||||
for (const Symbol& sym : commonSymbolVec)
|
||||
{
|
||||
Seek(s_strtabOffset + sym.nameOffset);
|
||||
std::string name = ReadString();
|
||||
commonSymbols[name] = sym.size;
|
||||
}
|
||||
|
||||
return commonSymbols;
|
||||
}
|
||||
Vendored
-30
@@ -1,30 +0,0 @@
|
||||
// Copyright(c) 2016 YamaArashi
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef ELF_H
|
||||
#define ELF_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
std::map<std::string, std::uint32_t> GetCommonSymbols(std::string path);
|
||||
|
||||
#endif // ELF_H
|
||||
Vendored
-173
@@ -1,173 +0,0 @@
|
||||
// Copyright(c) 2016 YamaArashi
|
||||
//
|
||||
// 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 <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include "ramscrgen.h"
|
||||
#include "sym_file.h"
|
||||
#include "elf.h"
|
||||
|
||||
void HandleCommonInclude(std::string filename, std::string sourcePath, std::string symOrderPath, std::string lang)
|
||||
{
|
||||
auto commonSymbols = GetCommonSymbols(sourcePath + "/" + filename);
|
||||
|
||||
std::size_t dotIndex = filename.find_last_of('.');
|
||||
|
||||
if (dotIndex == std::string::npos)
|
||||
FATAL_ERROR("error: \"%s\" doesn't have a file extension\n", filename.c_str());
|
||||
|
||||
std::string symOrderFilename = filename.substr(0, dotIndex + 1) + "txt";
|
||||
|
||||
SymFile symFile(symOrderPath + "/" + symOrderFilename);
|
||||
|
||||
while (!symFile.IsAtEnd())
|
||||
{
|
||||
symFile.HandleLangConditional(lang);
|
||||
|
||||
std::string label = symFile.GetLabel(false);
|
||||
|
||||
if (label.length() == 0)
|
||||
{
|
||||
unsigned long length;
|
||||
if (symFile.ReadInteger(length))
|
||||
{
|
||||
if (length & 3)
|
||||
symFile.RaiseWarning("gap length %d is not multiple of 4", length);
|
||||
printf(". += 0x%lX;\n", length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (commonSymbols.count(label) == 0)
|
||||
symFile.RaiseError("no common symbol named \"%s\"", label.c_str());
|
||||
unsigned long size = commonSymbols[label];
|
||||
int alignment = 4;
|
||||
if (size > 4)
|
||||
alignment = 8;
|
||||
if (size > 8)
|
||||
alignment = 16;
|
||||
printf(". = ALIGN(%d);\n", alignment);
|
||||
printf("%s = .;\n", label.c_str());
|
||||
printf(". += 0x%lX;\n", size);
|
||||
}
|
||||
|
||||
symFile.ExpectEmptyRestOfLine();
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertSymFile(std::string filename, std::string sectionName, std::string lang, bool common, std::string sourcePath, std::string commonSymPath)
|
||||
{
|
||||
SymFile symFile(filename);
|
||||
|
||||
while (!symFile.IsAtEnd())
|
||||
{
|
||||
symFile.HandleLangConditional(lang);
|
||||
|
||||
Directive directive = symFile.GetDirective();
|
||||
|
||||
switch (directive)
|
||||
{
|
||||
case Directive::Include:
|
||||
{
|
||||
std::string incFilename = symFile.ReadPath();
|
||||
symFile.ExpectEmptyRestOfLine();
|
||||
printf(". = ALIGN(4);\n");
|
||||
if (common)
|
||||
HandleCommonInclude(incFilename, sourcePath, commonSymPath, lang);
|
||||
else
|
||||
printf("%s(%s);\n", incFilename.c_str(), sectionName.c_str());
|
||||
break;
|
||||
}
|
||||
case Directive::Space:
|
||||
{
|
||||
unsigned long length;
|
||||
if (!symFile.ReadInteger(length))
|
||||
symFile.RaiseError("expected integer after .space directive");
|
||||
symFile.ExpectEmptyRestOfLine();
|
||||
printf(". += 0x%lX;\n", length);
|
||||
break;
|
||||
}
|
||||
case Directive::Align:
|
||||
{
|
||||
unsigned long amount;
|
||||
if (!symFile.ReadInteger(amount))
|
||||
symFile.RaiseError("expected integer after .align directive");
|
||||
if (amount > 4)
|
||||
symFile.RaiseError("max alignment amount is 4");
|
||||
amount = 1UL << amount;
|
||||
symFile.ExpectEmptyRestOfLine();
|
||||
printf(". = ALIGN(%lu);\n", amount);
|
||||
break;
|
||||
}
|
||||
case Directive::Unknown:
|
||||
{
|
||||
std::string label = symFile.GetLabel();
|
||||
|
||||
if (label.length() != 0)
|
||||
{
|
||||
printf("%s = .;\n", label.c_str());
|
||||
}
|
||||
|
||||
symFile.ExpectEmptyRestOfLine();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s SECTION_NAME SYM_FILE LANG [-c SRC_PATH,COMMON_SYM_PATH]", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool common = false;
|
||||
std::string sectionName = std::string(argv[1]);
|
||||
std::string symFileName = std::string(argv[2]);
|
||||
std::string lang = std::string(argv[3]);
|
||||
std::string sourcePath;
|
||||
std::string commonSymPath;
|
||||
|
||||
if (argc > 4)
|
||||
{
|
||||
if (std::strcmp(argv[4], "-c") != 0)
|
||||
FATAL_ERROR("error: unrecognized argument \"%s\"\n", argv[4]);
|
||||
|
||||
if (argc < 6)
|
||||
FATAL_ERROR("error: missing SRC_PATH,COMMON_SYM_PATH after \"-c\"\n");
|
||||
|
||||
common = true;
|
||||
std::string paths = std::string(argv[5]);
|
||||
std::size_t commaPos = paths.find(',');
|
||||
|
||||
if (commaPos == std::string::npos)
|
||||
FATAL_ERROR("error: missing comma in argument after \"-c\"\n");
|
||||
|
||||
sourcePath = paths.substr(0, commaPos);
|
||||
commonSymPath = paths.substr(commaPos + 1);
|
||||
}
|
||||
|
||||
ConvertSymFile(symFileName, sectionName, lang, common, sourcePath, commonSymPath);
|
||||
return 0;
|
||||
}
|
||||
Vendored
-49
@@ -1,49 +0,0 @@
|
||||
// Copyright(c) 2016 YamaArashi
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef RAMSCRGEN_H
|
||||
#define RAMSCRGEN_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define FATAL_ERROR(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
std::fprintf(stderr, format, __VA_ARGS__); \
|
||||
std::exit(1); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define FATAL_ERROR(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
std::fprintf(stderr, format, ##__VA_ARGS__); \
|
||||
std::exit(1); \
|
||||
} while (0)
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
const int kMaxPath = 256;
|
||||
|
||||
#endif // RAMSCRGEN_H
|
||||
Vendored
-492
@@ -1,492 +0,0 @@
|
||||
// Copyright(c) 2016 YamaArashi
|
||||
//
|
||||
// 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 <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <climits>
|
||||
#include "ramscrgen.h"
|
||||
#include "sym_file.h"
|
||||
#include "char_util.h"
|
||||
|
||||
SymFile::SymFile(std::string filename) : m_filename(filename)
|
||||
{
|
||||
FILE *fp = std::fopen(filename.c_str(), "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", filename.c_str());
|
||||
|
||||
std::fseek(fp, 0, SEEK_END);
|
||||
|
||||
m_size = std::ftell(fp);
|
||||
|
||||
if (m_size < 0)
|
||||
FATAL_ERROR("File size of \"%s\" is less than zero.\n", filename.c_str());
|
||||
|
||||
m_buffer = new char[m_size + 1];
|
||||
|
||||
std::rewind(fp);
|
||||
|
||||
if (std::fread(m_buffer, m_size, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read \"%s\".\n", filename.c_str());
|
||||
|
||||
m_buffer[m_size] = 0;
|
||||
|
||||
std::fclose(fp);
|
||||
|
||||
m_pos = 0;
|
||||
m_lineNum = 1;
|
||||
m_lineStart = 0;
|
||||
m_inLangConditional = false;
|
||||
|
||||
RemoveComments();
|
||||
}
|
||||
|
||||
SymFile::SymFile(SymFile&& other) : m_filename(std::move(other.m_filename))
|
||||
{
|
||||
m_buffer = other.m_buffer;
|
||||
m_pos = other.m_pos;
|
||||
m_size = other.m_size;
|
||||
m_lineNum = other.m_lineNum;
|
||||
m_lineStart = other.m_lineStart;
|
||||
|
||||
other.m_buffer = nullptr;
|
||||
}
|
||||
|
||||
SymFile::~SymFile()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
// Removes comments to simplify further processing.
|
||||
// It stops upon encountering a null character,
|
||||
// which may or may not be the end of file marker.
|
||||
// If it's not, the error will be caught later.
|
||||
void SymFile::RemoveComments()
|
||||
{
|
||||
long pos = 0;
|
||||
char stringChar = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (m_buffer[pos] == 0)
|
||||
return;
|
||||
|
||||
if (stringChar != 0)
|
||||
{
|
||||
if (m_buffer[pos] == '\\' && m_buffer[pos + 1] == stringChar)
|
||||
{
|
||||
pos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_buffer[pos] == stringChar)
|
||||
stringChar = 0;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
else if (m_buffer[pos] == '@' && (pos == 0 || m_buffer[pos - 1] != '\\'))
|
||||
{
|
||||
while (m_buffer[pos] != '\n' && m_buffer[pos] != 0)
|
||||
m_buffer[pos++] = ' ';
|
||||
}
|
||||
else if (m_buffer[pos] == '/' && m_buffer[pos + 1] == '*')
|
||||
{
|
||||
m_buffer[pos++] = ' ';
|
||||
m_buffer[pos++] = ' ';
|
||||
|
||||
char commentStringChar = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (m_buffer[pos] == 0)
|
||||
return;
|
||||
|
||||
if (commentStringChar != 0)
|
||||
{
|
||||
if (m_buffer[pos] == '\\' && m_buffer[pos + 1] == commentStringChar)
|
||||
{
|
||||
m_buffer[pos++] = ' ';
|
||||
m_buffer[pos++] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_buffer[pos] == commentStringChar)
|
||||
commentStringChar = 0;
|
||||
if (m_buffer[pos] != '\n')
|
||||
m_buffer[pos] = ' ';
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_buffer[pos] == '*' && m_buffer[pos + 1] == '/')
|
||||
{
|
||||
m_buffer[pos++] = ' ';
|
||||
m_buffer[pos++] = ' ';
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_buffer[pos] == '"' || m_buffer[pos] == '\'')
|
||||
commentStringChar = m_buffer[pos];
|
||||
if (m_buffer[pos] != '\n')
|
||||
m_buffer[pos] = ' ';
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_buffer[pos] == '"' || m_buffer[pos] == '\'')
|
||||
stringChar = m_buffer[pos];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if we're at a particular directive and if so, consumes it.
|
||||
// Returns whether the directive was found.
|
||||
bool SymFile::CheckForDirective(std::string name)
|
||||
{
|
||||
long i;
|
||||
long length = static_cast<long>(name.length());
|
||||
|
||||
for (i = 0; i < length && m_pos + i < m_size; i++)
|
||||
if (name[i] != m_buffer[m_pos + i])
|
||||
return false;
|
||||
|
||||
if (i < length)
|
||||
return false;
|
||||
|
||||
m_pos += length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Checks if we're at a known directive and if so, consumes it.
|
||||
// Returns which directive was found.
|
||||
Directive SymFile::GetDirective()
|
||||
{
|
||||
SkipWhitespace();
|
||||
|
||||
if (CheckForDirective(".include"))
|
||||
return Directive::Include;
|
||||
else if (CheckForDirective(".space"))
|
||||
return Directive::Space;
|
||||
else if (CheckForDirective(".align"))
|
||||
return Directive::Align;
|
||||
else
|
||||
return Directive::Unknown;
|
||||
}
|
||||
|
||||
// Checks if we're at label.
|
||||
// Returns the name if so and an empty string if not.
|
||||
std::string SymFile::GetLabel(bool requireColon)
|
||||
{
|
||||
long start = m_pos;
|
||||
long pos = m_pos;
|
||||
|
||||
if (IsIdentifierStartingChar(m_buffer[pos]))
|
||||
{
|
||||
pos++;
|
||||
|
||||
while (IsIdentifierChar(m_buffer[pos]))
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (requireColon)
|
||||
{
|
||||
if (m_buffer[pos] == ':')
|
||||
{
|
||||
if (pos != start)
|
||||
m_pos = pos + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = start;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pos = pos;
|
||||
}
|
||||
|
||||
return std::string(&m_buffer[start], pos - start);
|
||||
}
|
||||
|
||||
// Skips tabs and spaces.
|
||||
void SymFile::SkipWhitespace()
|
||||
{
|
||||
while (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ')
|
||||
m_pos++;
|
||||
}
|
||||
|
||||
// Reads include path.
|
||||
std::string SymFile::ReadPath()
|
||||
{
|
||||
SkipWhitespace();
|
||||
|
||||
if (m_buffer[m_pos] != '"')
|
||||
RaiseError("expected file path");
|
||||
|
||||
m_pos++;
|
||||
|
||||
int length = 0;
|
||||
long startPos = m_pos;
|
||||
|
||||
while (m_buffer[m_pos] != '"')
|
||||
{
|
||||
unsigned char c = m_buffer[m_pos++];
|
||||
|
||||
if (c == 0)
|
||||
{
|
||||
if (m_pos >= m_size)
|
||||
RaiseError("unexpected EOF in include string");
|
||||
else
|
||||
RaiseError("unexpected null character in include string");
|
||||
}
|
||||
|
||||
if (!IsAsciiPrintable(c))
|
||||
RaiseError("unexpected character '\\x%02X' in include string", c);
|
||||
|
||||
// Don't bother allowing any escape sequences.
|
||||
if (c == '\\')
|
||||
{
|
||||
c = m_buffer[m_pos];
|
||||
RaiseError("unexpected escape '\\%c' in include string", c);
|
||||
}
|
||||
|
||||
length++;
|
||||
|
||||
if (length > kMaxPath)
|
||||
RaiseError("path is too long");
|
||||
}
|
||||
|
||||
m_pos++; // Go past the right quote.
|
||||
|
||||
return std::string(&m_buffer[startPos], length);
|
||||
}
|
||||
|
||||
// If we're at a comma, consumes it.
|
||||
// Returns whether a comma was found.
|
||||
bool SymFile::ConsumeComma()
|
||||
{
|
||||
if (m_buffer[m_pos] == ',')
|
||||
{
|
||||
m_pos++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Converts digit character to numerical value.
|
||||
static int ConvertDigit(char c, int radix)
|
||||
{
|
||||
int digit;
|
||||
|
||||
if (c >= '0' && c <= '9')
|
||||
digit = c - '0';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
digit = 10 + c - 'A';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
digit = 10 + c - 'a';
|
||||
else
|
||||
return -1;
|
||||
|
||||
return (digit < radix) ? digit : -1;
|
||||
}
|
||||
|
||||
// Reads an integer.
|
||||
bool SymFile::ReadInteger(unsigned long& n)
|
||||
{
|
||||
SkipWhitespace();
|
||||
|
||||
if (!IsAsciiDigit(m_buffer[m_pos]))
|
||||
return false;
|
||||
|
||||
int startPos = m_pos;
|
||||
int radix = 10;
|
||||
|
||||
if (m_buffer[m_pos] == '0' && m_buffer[m_pos + 1] == 'x')
|
||||
{
|
||||
radix = 16;
|
||||
m_pos += 2;
|
||||
}
|
||||
|
||||
unsigned long cutoff = ULONG_MAX / radix;
|
||||
unsigned long cutoffRemainder = ULONG_MAX % radix;
|
||||
int digit;
|
||||
|
||||
n = 0;
|
||||
|
||||
while ((digit = ConvertDigit(m_buffer[m_pos], radix)) != -1)
|
||||
{
|
||||
if (n < cutoff || (n == cutoff && (unsigned long)digit <= cutoffRemainder))
|
||||
{
|
||||
n = n * radix + digit;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pos++;
|
||||
|
||||
while (ConvertDigit(m_buffer[m_pos], radix) != -1)
|
||||
m_pos++;
|
||||
|
||||
RaiseError("integer is too large (%s)", std::string(&m_buffer[startPos], m_pos - startPos).c_str());
|
||||
}
|
||||
|
||||
m_pos++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Asserts that the rest of the line is empty and moves to the next one.
|
||||
void SymFile::ExpectEmptyRestOfLine()
|
||||
{
|
||||
SkipWhitespace();
|
||||
|
||||
if (m_buffer[m_pos] == 0)
|
||||
{
|
||||
if (m_pos >= m_size)
|
||||
RaiseWarning("file doesn't end with newline");
|
||||
else
|
||||
RaiseError("unexpected null character");
|
||||
}
|
||||
else if (m_buffer[m_pos] == '\n')
|
||||
{
|
||||
m_pos++;
|
||||
m_lineStart = m_pos;
|
||||
m_lineNum++;
|
||||
}
|
||||
else if (m_buffer[m_pos] == '\r')
|
||||
{
|
||||
RaiseError("only Unix-style LF newlines are supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseError("junk at end of line");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SymFile::SkipLine()
|
||||
{
|
||||
while (m_buffer[m_pos] != 0 && m_buffer[m_pos] != '\n')
|
||||
m_pos++;
|
||||
|
||||
if (m_buffer[m_pos] == '\n')
|
||||
m_pos++;
|
||||
}
|
||||
|
||||
// Checks if we're at the end of the file.
|
||||
bool SymFile::IsAtEnd()
|
||||
{
|
||||
return (m_pos >= m_size);
|
||||
}
|
||||
|
||||
void SymFile::HandleLangConditional(std::string lang)
|
||||
{
|
||||
if (m_buffer[m_pos] != '#')
|
||||
return;
|
||||
|
||||
m_pos++;
|
||||
|
||||
if (CheckForDirective("begin"))
|
||||
{
|
||||
if (m_inLangConditional)
|
||||
RaiseError("already inside language conditional");
|
||||
|
||||
SkipWhitespace();
|
||||
|
||||
std::string label = GetLabel(false);
|
||||
|
||||
if (label.length() == 0)
|
||||
RaiseError("no language name after #begin");
|
||||
|
||||
ExpectEmptyRestOfLine();
|
||||
|
||||
if (lang == label)
|
||||
{
|
||||
m_inLangConditional = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!IsAtEnd() && m_buffer[m_pos] != '#')
|
||||
SkipLine();
|
||||
|
||||
if (m_buffer[m_pos] != '#')
|
||||
RaiseError("unterminated language conditional");
|
||||
|
||||
m_pos++;
|
||||
|
||||
if (!CheckForDirective("end"))
|
||||
RaiseError("expected #end");
|
||||
|
||||
ExpectEmptyRestOfLine();
|
||||
}
|
||||
}
|
||||
else if (CheckForDirective("end"))
|
||||
{
|
||||
if (!m_inLangConditional)
|
||||
RaiseError("not inside language conditional");
|
||||
|
||||
m_inLangConditional = false;
|
||||
|
||||
ExpectEmptyRestOfLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseError("unknown # directive");
|
||||
}
|
||||
}
|
||||
|
||||
// Reports a diagnostic message.
|
||||
void SymFile::ReportDiagnostic(const char* type, const char* format, std::va_list args)
|
||||
{
|
||||
const int bufferSize = 1024;
|
||||
char buffer[bufferSize];
|
||||
std::vsnprintf(buffer, bufferSize, format, args);
|
||||
std::fprintf(stderr, "%s:%ld: %s: %s\n", m_filename.c_str(), m_lineNum, type, buffer);
|
||||
}
|
||||
|
||||
#define DO_REPORT(type) \
|
||||
do \
|
||||
{ \
|
||||
std::va_list args; \
|
||||
va_start(args, format); \
|
||||
ReportDiagnostic(type, format, args); \
|
||||
va_end(args); \
|
||||
} while (0)
|
||||
|
||||
// Reports an error diagnostic and terminates the program.
|
||||
void SymFile::RaiseError(const char* format, ...)
|
||||
{
|
||||
DO_REPORT("error");
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Reports a warning diagnostic.
|
||||
void SymFile::RaiseWarning(const char* format, ...)
|
||||
{
|
||||
DO_REPORT("warning");
|
||||
}
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
rsfont
|
||||
Vendored
-19
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2015-2016 YamaArashi
|
||||
|
||||
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.
|
||||
Vendored
-20
@@ -1,20 +0,0 @@
|
||||
CC = gcc
|
||||
|
||||
CFLAGS = -Wall -Wextra -Werror -std=c11 -O2 -s -DPNG_SKIP_SETJMP_CHECK
|
||||
CFLAGS += $(shell pkg-config --cflags libpng)
|
||||
|
||||
LIBS = -lpng -lz
|
||||
LDFLAGS += $(shell pkg-config --libs-only-L libpng)
|
||||
|
||||
SRCS = main.c convert_png.c util.c font.c
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: rsfont
|
||||
@:
|
||||
|
||||
rsfont: $(SRCS) convert_png.h gfx.h global.h util.h font.h
|
||||
$(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
$(RM) rsfont rsfont.exe
|
||||
Vendored
-169
@@ -1,169 +0,0 @@
|
||||
// Copyright (c) 2015 YamaArashi
|
||||
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
#include <png.h>
|
||||
#include "global.h"
|
||||
#include "convert_png.h"
|
||||
#include "gfx.h"
|
||||
|
||||
void ReadPng(char *path, struct Image *image)
|
||||
{
|
||||
FILE *fp = fopen(path, "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
|
||||
|
||||
unsigned char sig[8];
|
||||
|
||||
if (fread(sig, 8, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read PNG signature from \"%s\".\n", path);
|
||||
|
||||
if (png_sig_cmp(sig, 0, 8))
|
||||
FATAL_ERROR("\"%s\" does not have a valid PNG signature.\n", path);
|
||||
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
|
||||
if (!png_ptr)
|
||||
FATAL_ERROR("Failed to create PNG read struct.\n");
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
|
||||
if (!info_ptr)
|
||||
FATAL_ERROR("Failed to create PNG info struct.\n");
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
FATAL_ERROR("Failed to init I/O for reading \"%s\".\n", path);
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
png_set_sig_bytes(png_ptr, 8);
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
|
||||
|
||||
if (bit_depth != image->bitDepth)
|
||||
FATAL_ERROR("\"%s\" has a bit depth of %d, but the expected bit depth is %d.\n", path, bit_depth, image->bitDepth);
|
||||
|
||||
int color_type = png_get_color_type(png_ptr, info_ptr);
|
||||
|
||||
if (color_type != PNG_COLOR_TYPE_GRAY && color_type != PNG_COLOR_TYPE_PALETTE)
|
||||
FATAL_ERROR("\"%s\" has an unsupported color type.\n", path);
|
||||
|
||||
// Check if the image has a palette so that we can tell if the colors need to be inverted later.
|
||||
// Don't read the palette because it's not needed for now.
|
||||
image->hasPalette = (color_type == PNG_COLOR_TYPE_PALETTE);
|
||||
|
||||
image->width = png_get_image_width(png_ptr, info_ptr);
|
||||
image->height = png_get_image_height(png_ptr, info_ptr);
|
||||
|
||||
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||
|
||||
image->pixels = malloc(image->height * rowbytes);
|
||||
|
||||
if (image->pixels == NULL)
|
||||
FATAL_ERROR("Failed to allocate pixel buffer.\n");
|
||||
|
||||
png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));
|
||||
|
||||
if (row_pointers == NULL)
|
||||
FATAL_ERROR("Failed to allocate row pointers.\n");
|
||||
|
||||
for (int i = 0; i < image->height; i++)
|
||||
row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes));
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
FATAL_ERROR("Error reading from \"%s\".\n", path);
|
||||
|
||||
png_read_image(png_ptr, row_pointers);
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
|
||||
free(row_pointers);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *palette)
|
||||
{
|
||||
png_colorp colors = malloc(palette->numColors * sizeof(png_color));
|
||||
|
||||
if (colors == NULL)
|
||||
FATAL_ERROR("Failed to allocate PNG palette.\n");
|
||||
|
||||
for (int i = 0; i < palette->numColors; i++) {
|
||||
colors[i].red = palette->colors[i].red;
|
||||
colors[i].green = palette->colors[i].green;
|
||||
colors[i].blue = palette->colors[i].blue;
|
||||
}
|
||||
|
||||
png_set_PLTE(png_ptr, info_ptr, colors, palette->numColors);
|
||||
|
||||
free(colors);
|
||||
}
|
||||
|
||||
void WritePng(char *path, struct Image *image)
|
||||
{
|
||||
FILE *fp = fopen(path, "wb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
|
||||
|
||||
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
|
||||
if (!png_ptr)
|
||||
FATAL_ERROR("Failed to create PNG write struct.\n");
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
|
||||
if (!info_ptr)
|
||||
FATAL_ERROR("Failed to create PNG info struct.\n");
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
FATAL_ERROR("Failed to init I/O for writing \"%s\".\n", path);
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
FATAL_ERROR("Error writing header for \"%s\".\n", path);
|
||||
|
||||
int color_type = image->hasPalette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY;
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
|
||||
image->bitDepth, color_type, PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
|
||||
if (image->hasPalette) {
|
||||
SetPngPalette(png_ptr, info_ptr, &image->palette);
|
||||
|
||||
if (image->hasTransparency) {
|
||||
png_byte trans = 0;
|
||||
png_set_tRNS(png_ptr, info_ptr, &trans, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));
|
||||
|
||||
if (row_pointers == NULL)
|
||||
FATAL_ERROR("Failed to allocate row pointers.\n");
|
||||
|
||||
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||
|
||||
for (int i = 0; i < image->height; i++)
|
||||
row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes));
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
FATAL_ERROR("Error writing \"%s\".\n", path);
|
||||
|
||||
png_write_image(png_ptr, row_pointers);
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
FATAL_ERROR("Error ending write of \"%s\".\n", path);
|
||||
|
||||
png_write_end(png_ptr, NULL);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
free(row_pointers);
|
||||
}
|
||||
Vendored
-11
@@ -1,11 +0,0 @@
|
||||
// Copyright (c) 2015 YamaArashi
|
||||
|
||||
#ifndef CONVERT_PNG_H
|
||||
#define CONVERT_PNG_H
|
||||
|
||||
#include "gfx.h"
|
||||
|
||||
void ReadPng(char *path, struct Image *image);
|
||||
void WritePng(char *path, struct Image *image);
|
||||
|
||||
#endif // CONVERT_PNG_H
|
||||
Vendored
-455
@@ -1,455 +0,0 @@
|
||||
// Copyright(c) 2015-2016 YamaArashi
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "global.h"
|
||||
#include "font.h"
|
||||
#include "gfx.h"
|
||||
#include "util.h"
|
||||
|
||||
unsigned char gFontPalette[][3] =
|
||||
{
|
||||
{0xFF, 0xFF, 0xFF}, // bg (white)
|
||||
{0x38, 0x38, 0x38}, // fg (dark grey)
|
||||
{0xD8, 0xD8, 0xD8}, // shadow (light grey)
|
||||
};
|
||||
|
||||
void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout)
|
||||
{
|
||||
for (int glyph = 0; glyph < numGlyphs; glyph++)
|
||||
{
|
||||
if (layout == 0)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint8_t srcRow = src[(glyph * 8) + i];
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 8) + i;
|
||||
dest[(y * 128) + x] = (srcRow >> (7 - j)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// layout type 1
|
||||
|
||||
int tile1Offset = glyph * 16;
|
||||
int tile2Offset = tile1Offset + 8;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint8_t srcRow = src[tile1Offset + i];
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 16) + i;
|
||||
dest[(y * 128) + x] = (srcRow >> (7 - j)) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint8_t srcRow = src[tile2Offset + i];
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 16) + 8 + i;
|
||||
dest[(y * 128) + x] = (srcRow >> (7 - j)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertToTiles1Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout)
|
||||
{
|
||||
for (int glyph = 0; glyph < numGlyphs; glyph++)
|
||||
{
|
||||
if (layout == 0)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint8_t destRow = 0;
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 8) + i;
|
||||
unsigned char color = src[(y * 128) + x];
|
||||
|
||||
if (color > 1)
|
||||
FATAL_ERROR("More than 2 colors in 1 BPP font.\n");
|
||||
|
||||
destRow <<= 1;
|
||||
destRow |= color;
|
||||
}
|
||||
|
||||
dest[(glyph * 8) + i] = destRow;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// layout type 1
|
||||
|
||||
int tile1Offset = glyph * 16;
|
||||
int tile2Offset = tile1Offset + 8;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint8_t destRow = 0;
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 16) + i;
|
||||
unsigned char color = src[(y * 128) + x];
|
||||
|
||||
if (color > 1)
|
||||
FATAL_ERROR("More than 2 colors in 1 BPP font.\n");
|
||||
|
||||
destRow <<= 1;
|
||||
destRow |= color;
|
||||
}
|
||||
|
||||
dest[tile1Offset + i] = destRow;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint8_t destRow = 0;
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 16) + 8 + i;
|
||||
unsigned char color = src[(y * 128) + x];
|
||||
|
||||
if (color > 1)
|
||||
FATAL_ERROR("More than 2 colors in 1 BPP font.\n");
|
||||
|
||||
destRow <<= 1;
|
||||
destRow |= color;
|
||||
}
|
||||
|
||||
dest[tile2Offset + i] = destRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertFromTiles4Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout)
|
||||
{
|
||||
static unsigned char table[16] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1,
|
||||
};
|
||||
|
||||
for (int glyph = 0; glyph < numGlyphs; glyph++)
|
||||
{
|
||||
if (layout == 0)
|
||||
{
|
||||
int offset = glyph * 32;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint32_t srcRow = (src[offset + 3] << 24)
|
||||
| (src[offset + 2] << 16)
|
||||
| (src[offset + 1] << 8)
|
||||
| src[offset];
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 8) + i;
|
||||
dest[(y * 128) + x] = table[srcRow & 0xF];
|
||||
srcRow >>= 4;
|
||||
}
|
||||
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int tile1Offset;
|
||||
int tile2Offset;
|
||||
|
||||
if (layout == 1)
|
||||
{
|
||||
tile1Offset = glyph * 64;
|
||||
tile2Offset = tile1Offset + 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
tile1Offset = ((glyph / 16) * 1024) + ((glyph % 16) * 32);
|
||||
tile2Offset = tile1Offset + 512;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint32_t srcRow = (src[tile1Offset + 3] << 24)
|
||||
| (src[tile1Offset + 2] << 16)
|
||||
| (src[tile1Offset + 1] << 8)
|
||||
| src[tile1Offset];
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 16) + i;
|
||||
dest[(y * 128) + x] = table[srcRow & 0xF];
|
||||
srcRow >>= 4;
|
||||
}
|
||||
|
||||
tile1Offset += 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint32_t srcRow = (src[tile2Offset + 3] << 24)
|
||||
| (src[tile2Offset + 2] << 16)
|
||||
| (src[tile2Offset + 1] << 8)
|
||||
| src[tile2Offset];
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 16) + 8 + i;
|
||||
dest[(y * 128) + x] = table[srcRow & 0xF];
|
||||
srcRow >>= 4;
|
||||
}
|
||||
|
||||
tile2Offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertToTiles4Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout)
|
||||
{
|
||||
static unsigned char table[3] =
|
||||
{
|
||||
0, 15, 14,
|
||||
};
|
||||
|
||||
for (int glyph = 0; glyph < numGlyphs; glyph++)
|
||||
{
|
||||
if (layout == 0)
|
||||
{
|
||||
int offset = glyph * 32;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint32_t destRow = 0;
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 8) + i;
|
||||
unsigned char color = src[(y * 128) + x];
|
||||
|
||||
if (color > 2)
|
||||
FATAL_ERROR("More than 3 colors in 4 BPP font.\n");
|
||||
|
||||
destRow >>= 4;
|
||||
destRow |= (table[color] << 28);
|
||||
}
|
||||
|
||||
dest[offset] = destRow & 0xFF;
|
||||
dest[offset + 1] = (destRow >> 8) & 0xFF;
|
||||
dest[offset + 2] = (destRow >> 16) & 0xFF;
|
||||
dest[offset + 3] = (destRow >> 24) & 0xFF;
|
||||
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int tile1Offset;
|
||||
int tile2Offset;
|
||||
|
||||
if (layout == 1)
|
||||
{
|
||||
tile1Offset = glyph * 64;
|
||||
tile2Offset = tile1Offset + 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
tile1Offset = ((glyph / 16) * 1024) + ((glyph % 16) * 32);
|
||||
tile2Offset = tile1Offset + 512;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint32_t destRow = 0;
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 16) + i;
|
||||
unsigned char color = src[(y * 128) + x];
|
||||
|
||||
if (color > 2)
|
||||
FATAL_ERROR("More than 3 colors in 4 BPP font.\n");
|
||||
|
||||
destRow >>= 4;
|
||||
destRow |= (table[color] << 28);
|
||||
}
|
||||
|
||||
dest[tile1Offset] = destRow & 0xFF;
|
||||
dest[tile1Offset + 1] = (destRow >> 8) & 0xFF;
|
||||
dest[tile1Offset + 2] = (destRow >> 16) & 0xFF;
|
||||
dest[tile1Offset + 3] = (destRow >> 24) & 0xFF;
|
||||
|
||||
tile1Offset += 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint32_t destRow = 0;
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int x = ((glyph % 16) * 8) + j;
|
||||
int y = ((glyph / 16) * 16) + 8 + i;
|
||||
unsigned char color = src[(y * 128) + x];
|
||||
|
||||
if (color > 2)
|
||||
FATAL_ERROR("More than 3 colors in 4 BPP font.\n");
|
||||
|
||||
destRow >>= 4;
|
||||
destRow |= (table[color] << 28);
|
||||
}
|
||||
|
||||
dest[tile2Offset] = destRow & 0xFF;
|
||||
dest[tile2Offset + 1] = (destRow >> 8) & 0xFF;
|
||||
dest[tile2Offset + 2] = (destRow >> 16) & 0xFF;
|
||||
dest[tile2Offset + 3] = (destRow >> 24) & 0xFF;
|
||||
|
||||
tile2Offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SetFontPalette(struct Image *image)
|
||||
{
|
||||
image->hasPalette = true;
|
||||
|
||||
image->palette.numColors = 3;
|
||||
|
||||
for (int i = 0; i < image->palette.numColors; i++)
|
||||
{
|
||||
image->palette.colors[i].red = gFontPalette[i][0];
|
||||
image->palette.colors[i].green = gFontPalette[i][1];
|
||||
image->palette.colors[i].blue = gFontPalette[i][2];
|
||||
}
|
||||
|
||||
image->hasTransparency = false;
|
||||
}
|
||||
|
||||
int CalcFileSize(int numGlyphs, int bpp, int layout)
|
||||
{
|
||||
if (layout == 2)
|
||||
{
|
||||
// assume 4 BPP
|
||||
int numFullRows = numGlyphs / 16;
|
||||
int remainder = numGlyphs % 16;
|
||||
int fullRowsSize = numFullRows * 1024;
|
||||
int remainderSize = 0;
|
||||
|
||||
if (remainder != 0)
|
||||
remainderSize = 1024 - (16 - remainder) * 32;
|
||||
|
||||
return fullRowsSize + remainderSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
int tilesPerGlyph = layout > 0 ? 2 : 1;
|
||||
int bytesPerTile = 8 * bpp;
|
||||
return numGlyphs * tilesPerGlyph * bytesPerTile;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout)
|
||||
{
|
||||
int fileSize;
|
||||
unsigned char *buffer = ReadWholeFile(path, &fileSize);
|
||||
|
||||
int expectedFileSize = CalcFileSize(numGlyphs, bpp, layout);
|
||||
|
||||
if (fileSize != expectedFileSize)
|
||||
FATAL_ERROR("The file size is %d but should be %d.\n", fileSize, expectedFileSize);
|
||||
|
||||
int numRows = (numGlyphs + 15) / 16;
|
||||
int rowHeight = layout > 0 ? 16 : 8;
|
||||
|
||||
image->width = 128;
|
||||
image->height = numRows * rowHeight;
|
||||
image->bitDepth = 8;
|
||||
image->pixels = calloc(image->width * image->height, 1);
|
||||
|
||||
if (image->pixels == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
|
||||
if (bpp == 1)
|
||||
ConvertFromTiles1Bpp(buffer, image->pixels, numGlyphs, layout);
|
||||
else
|
||||
ConvertFromTiles4Bpp(buffer, image->pixels, numGlyphs, layout);
|
||||
|
||||
free(buffer);
|
||||
|
||||
SetFontPalette(image);
|
||||
}
|
||||
|
||||
void WriteFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout)
|
||||
{
|
||||
if (image->width != 128)
|
||||
FATAL_ERROR("The width of the font image (%d) is not 128.\n", image->width);
|
||||
|
||||
int numRows = (numGlyphs + 15) / 16;
|
||||
int rowHeight = layout > 0 ? 16 : 8;
|
||||
int expectedHeight = numRows * rowHeight;
|
||||
|
||||
if (image->height < expectedHeight)
|
||||
FATAL_ERROR("The height of the font image (%d) is less than %d.\n", image->height, expectedHeight);
|
||||
|
||||
int fileSize = CalcFileSize(numGlyphs, bpp, layout);
|
||||
|
||||
unsigned char *buffer = calloc(fileSize, 1);
|
||||
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
|
||||
if (bpp == 1)
|
||||
ConvertToTiles1Bpp(image->pixels, buffer, numGlyphs, layout);
|
||||
else
|
||||
ConvertToTiles4Bpp(image->pixels, buffer, numGlyphs, layout);
|
||||
|
||||
WriteWholeFile(path, buffer, fileSize);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
Vendored
-30
@@ -1,30 +0,0 @@
|
||||
// Copyright(c) 2015-2016 YamaArashi
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "gfx.h"
|
||||
|
||||
void ReadFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout);
|
||||
void WriteFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout);
|
||||
|
||||
#endif // FONT_H
|
||||
Vendored
-50
@@ -1,50 +0,0 @@
|
||||
// Copyright(c) 2015-2016 YamaArashi
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef GFX_H
|
||||
#define GFX_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct Color
|
||||
{
|
||||
unsigned char red;
|
||||
unsigned char green;
|
||||
unsigned char blue;
|
||||
};
|
||||
|
||||
struct Palette
|
||||
{
|
||||
struct Color colors[256];
|
||||
int numColors;
|
||||
};
|
||||
|
||||
struct Image {
|
||||
int width;
|
||||
int height;
|
||||
int bitDepth;
|
||||
unsigned char *pixels;
|
||||
bool hasPalette;
|
||||
struct Palette palette;
|
||||
bool hasTransparency;
|
||||
};
|
||||
|
||||
#endif // GFX_H
|
||||
Vendored
-31
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2015 YamaArashi
|
||||
|
||||
#ifndef GLOBAL_H
|
||||
#define GLOBAL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define FATAL_ERROR(format, ...) \
|
||||
do { \
|
||||
fprintf(stderr, format, __VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#define UNUSED
|
||||
|
||||
#else
|
||||
|
||||
#define FATAL_ERROR(format, ...) \
|
||||
do { \
|
||||
fprintf(stderr, format, ##__VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#define UNUSED __attribute__((__unused__))
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // GLOBAL_H
|
||||
Vendored
-93
@@ -1,93 +0,0 @@
|
||||
// Copyright(c) 2015-2016 YamaArashi
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "global.h"
|
||||
#include "util.h"
|
||||
#include "gfx.h"
|
||||
#include "convert_png.h"
|
||||
#include "font.h"
|
||||
|
||||
int ExtensionToBpp(const char *extension)
|
||||
{
|
||||
if (!strcmp(extension, "1bpp"))
|
||||
return 1;
|
||||
else if (!strcmp(extension, "4bpp"))
|
||||
return 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 5)
|
||||
FATAL_ERROR("Usage: rsfont INPUT_FILE OUTPUT_FILE NUM_GLYPHS LAYOUT_TYPE\n");
|
||||
|
||||
char *inputPath = argv[1];
|
||||
char *outputPath = argv[2];
|
||||
char *inputFileExtension = GetFileExtension(inputPath);
|
||||
char *outputFileExtension = GetFileExtension(outputPath);
|
||||
|
||||
if (inputFileExtension == NULL)
|
||||
FATAL_ERROR("Input file \"%s\" has no extension.\n", inputPath);
|
||||
|
||||
if (outputFileExtension == NULL)
|
||||
FATAL_ERROR("Output file \"%s\" has no extension.\n", outputPath);
|
||||
|
||||
int numGlyphs;
|
||||
int bpp;
|
||||
int layout;
|
||||
|
||||
if (!ParseNumber(argv[3], NULL, 10, &numGlyphs))
|
||||
FATAL_ERROR("Failed to parse number of glyphs.\n");
|
||||
|
||||
if (!ParseNumber(argv[4], NULL, 10, &layout))
|
||||
FATAL_ERROR("Failed to parse layout type.\n");
|
||||
|
||||
if (layout < 0 || layout > 2)
|
||||
FATAL_ERROR("Layout type %d is invalid. Layout type must be 0, 1, or 2.\n", layout);
|
||||
|
||||
bool toPng;
|
||||
|
||||
if (!strcmp(inputFileExtension, "png") && (bpp = ExtensionToBpp(outputFileExtension)) != 0)
|
||||
toPng = false;
|
||||
else if ((bpp = ExtensionToBpp(inputFileExtension)) != 0 && !strcmp(outputFileExtension, "png"))
|
||||
toPng = true;
|
||||
else
|
||||
FATAL_ERROR("Don't know how to convert \"%s\" to \"%s\".\n", inputPath, outputPath);
|
||||
|
||||
if (bpp == 1 && layout == 2)
|
||||
FATAL_ERROR("Layout type 2 is not supported with 1 BPP fonts.\n");
|
||||
|
||||
struct Image image;
|
||||
|
||||
if (toPng)
|
||||
{
|
||||
ReadFont(inputPath, &image, numGlyphs, bpp, layout);
|
||||
WritePng(outputPath, &image);
|
||||
}
|
||||
else
|
||||
{
|
||||
image.bitDepth = 8;
|
||||
ReadPng(inputPath, &image);
|
||||
WriteFont(outputPath, &image, numGlyphs, bpp, layout);
|
||||
}
|
||||
}
|
||||
Vendored
-124
@@ -1,124 +0,0 @@
|
||||
// Copyright (c) 2015 YamaArashi
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include "global.h"
|
||||
#include "util.h"
|
||||
|
||||
bool ParseNumber(char *s, char **end, int radix, int *intValue)
|
||||
{
|
||||
char *localEnd;
|
||||
|
||||
if (end == NULL)
|
||||
end = &localEnd;
|
||||
|
||||
errno = 0;
|
||||
|
||||
const long longValue = strtol(s, end, radix);
|
||||
|
||||
if (*end == s)
|
||||
return false; // not a number
|
||||
|
||||
if ((longValue == LONG_MIN || longValue == LONG_MAX) && errno == ERANGE)
|
||||
return false;
|
||||
|
||||
if (longValue > INT_MAX)
|
||||
return false;
|
||||
|
||||
if (longValue < INT_MIN)
|
||||
return false;
|
||||
|
||||
*intValue = (int)longValue;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *GetFileExtension(char *path)
|
||||
{
|
||||
char *extension = path;
|
||||
|
||||
while (*extension != 0)
|
||||
extension++;
|
||||
|
||||
while (extension > path && *extension != '.')
|
||||
extension--;
|
||||
|
||||
if (extension == path)
|
||||
return NULL;
|
||||
|
||||
extension++;
|
||||
|
||||
if (*extension == 0)
|
||||
return NULL;
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
unsigned char *ReadWholeFile(char *path, int *size)
|
||||
{
|
||||
FILE *fp = fopen(path, "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
|
||||
*size = ftell(fp);
|
||||
|
||||
unsigned char *buffer = malloc(*size);
|
||||
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
|
||||
|
||||
rewind(fp);
|
||||
|
||||
if (fread(buffer, *size, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read \"%s\".\n", path);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount)
|
||||
{
|
||||
FILE *fp = fopen(path, "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
|
||||
*size = ftell(fp);
|
||||
|
||||
unsigned char *buffer = calloc(*size + padAmount, 1);
|
||||
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
|
||||
|
||||
rewind(fp);
|
||||
|
||||
if (fread(buffer, *size, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read \"%s\".\n", path);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void WriteWholeFile(char *path, void *buffer, int bufferSize)
|
||||
{
|
||||
FILE *fp = fopen(path, "wb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
|
||||
|
||||
if (fwrite(buffer, bufferSize, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to write to \"%s\".\n", path);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
Vendored
-14
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) 2015 YamaArashi
|
||||
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool ParseNumber(char *s, char **end, int radix, int *intValue);
|
||||
char *GetFileExtension(char *path);
|
||||
unsigned char *ReadWholeFile(char *path, int *size);
|
||||
unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount);
|
||||
void WriteWholeFile(char *path, void *buffer, int bufferSize);
|
||||
|
||||
#endif // UTIL_H
|
||||
Vendored
+11
-5
@@ -1,17 +1,23 @@
|
||||
CXX = g++
|
||||
CXX ?= g++
|
||||
|
||||
CXXFLAGS = -Wall -Werror -std=c++11 -O2
|
||||
|
||||
SRCS = scaninc.cpp c_file.cpp asm_file.cpp
|
||||
SRCS = scaninc.cpp c_file.cpp asm_file.cpp source_file.cpp
|
||||
|
||||
HEADERS := scaninc.h asm_file.h c_file.h
|
||||
HEADERS := scaninc.h asm_file.h c_file.h source_file.h
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: scaninc
|
||||
ifeq ($(OS),Windows_NT)
|
||||
EXE := .exe
|
||||
else
|
||||
EXE :=
|
||||
endif
|
||||
|
||||
all: scaninc$(EXE)
|
||||
@:
|
||||
|
||||
scaninc: $(SRCS) $(HEADERS)
|
||||
scaninc$(EXE): $(SRCS) $(HEADERS)
|
||||
$(CXX) $(CXXFLAGS) $(SRCS) -o $@ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
|
||||
Vendored
+8
-2
@@ -36,6 +36,11 @@ AsmFile::AsmFile(std::string path)
|
||||
|
||||
m_size = std::ftell(fp);
|
||||
|
||||
if (m_size < 0)
|
||||
FATAL_ERROR("File size of \"%s\" is less than zero.\n", path.c_str());
|
||||
else if (m_size == 0)
|
||||
return; // Empty file
|
||||
|
||||
m_buffer = new char[m_size];
|
||||
|
||||
std::rewind(fp);
|
||||
@@ -51,7 +56,7 @@ AsmFile::AsmFile(std::string path)
|
||||
|
||||
AsmFile::~AsmFile()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
if (m_size > 0) delete[] m_buffer;
|
||||
}
|
||||
|
||||
IncDirectiveType AsmFile::ReadUntilIncDirective(std::string &path)
|
||||
@@ -64,7 +69,8 @@ IncDirectiveType AsmFile::ReadUntilIncDirective(std::string &path)
|
||||
|
||||
IncDirectiveType incDirectiveType = IncDirectiveType::None;
|
||||
|
||||
if (PeekChar() == '.')
|
||||
char c = PeekChar();
|
||||
if (c == '.' || c == '#')
|
||||
{
|
||||
m_pos++;
|
||||
|
||||
|
||||
Vendored
+6
-1
@@ -33,6 +33,11 @@ CFile::CFile(std::string path)
|
||||
|
||||
m_size = std::ftell(fp);
|
||||
|
||||
if (m_size < 0)
|
||||
FATAL_ERROR("File size of \"%s\" is less than zero.\n", path.c_str());
|
||||
else if (m_size == 0)
|
||||
return; // Empty file
|
||||
|
||||
m_buffer = new char[m_size + 1];
|
||||
m_buffer[m_size] = 0;
|
||||
|
||||
@@ -49,7 +54,7 @@ CFile::CFile(std::string path)
|
||||
|
||||
CFile::~CFile()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
if (m_size > 0) delete[] m_buffer;
|
||||
}
|
||||
|
||||
void CFile::FindIncbins()
|
||||
|
||||
Vendored
+89
-68
@@ -24,9 +24,11 @@
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <tuple>
|
||||
#include <fstream>
|
||||
#include "scaninc.h"
|
||||
#include "asm_file.h"
|
||||
#include "c_file.h"
|
||||
#include "source_file.h"
|
||||
|
||||
bool CanOpenFile(std::string path)
|
||||
{
|
||||
@@ -39,14 +41,18 @@ bool CanOpenFile(std::string path)
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *const USAGE = "Usage: scaninc [-I INCLUDE_PATH] FILE_PATH\n";
|
||||
const char *const USAGE = "Usage: scaninc [-I INCLUDE_PATH] [-M DEPENDENCY_OUT_PATH] FILE_PATH\n";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::queue<std::string> filesToProcess;
|
||||
std::set<std::string> dependencies;
|
||||
std::set<std::string> dependencies_includes;
|
||||
|
||||
std::list<std::string> includeDirs;
|
||||
std::vector<std::string> includeDirs;
|
||||
|
||||
bool makeformat = false;
|
||||
std::string make_outfile;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
@@ -63,12 +69,19 @@ int main(int argc, char **argv)
|
||||
argv++;
|
||||
includeDir = std::string(argv[0]);
|
||||
}
|
||||
if (includeDir.back() != '/')
|
||||
if (!includeDir.empty() && includeDir.back() != '/')
|
||||
{
|
||||
includeDir += '/';
|
||||
}
|
||||
includeDirs.push_back(includeDir);
|
||||
}
|
||||
else if(arg.substr(0, 2) == "-M")
|
||||
{
|
||||
makeformat = true;
|
||||
argc--;
|
||||
argv++;
|
||||
make_outfile = std::string(argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
FATAL_ERROR(USAGE);
|
||||
@@ -83,83 +96,91 @@ int main(int argc, char **argv)
|
||||
|
||||
std::string initialPath(argv[0]);
|
||||
|
||||
std::size_t pos = initialPath.find_last_of('.');
|
||||
filesToProcess.push(initialPath);
|
||||
|
||||
if (pos == std::string::npos)
|
||||
FATAL_ERROR("no file extension in path \"%s\"\n", initialPath.c_str());
|
||||
|
||||
std::string extension = initialPath.substr(pos + 1);
|
||||
|
||||
std::string srcDir("");
|
||||
std::size_t slash = initialPath.rfind('/');
|
||||
if (slash != std::string::npos)
|
||||
while (!filesToProcess.empty())
|
||||
{
|
||||
srcDir = initialPath.substr(0, slash + 1);
|
||||
}
|
||||
includeDirs.push_back(srcDir);
|
||||
std::string filePath = filesToProcess.front();
|
||||
SourceFile file(filePath);
|
||||
filesToProcess.pop();
|
||||
|
||||
if (extension == "c" || extension == "h")
|
||||
{
|
||||
filesToProcess.push(initialPath);
|
||||
|
||||
while (!filesToProcess.empty())
|
||||
includeDirs.push_back(file.GetSrcDir());
|
||||
for (auto incbin : file.GetIncbins())
|
||||
{
|
||||
CFile file(filesToProcess.front());
|
||||
filesToProcess.pop();
|
||||
|
||||
file.FindIncbins();
|
||||
for (auto incbin : file.GetIncbins())
|
||||
dependencies.insert(incbin);
|
||||
}
|
||||
for (auto include : file.GetIncludes())
|
||||
{
|
||||
bool exists = false;
|
||||
std::string path("");
|
||||
for (auto includeDir : includeDirs)
|
||||
{
|
||||
dependencies.insert(incbin);
|
||||
}
|
||||
for (auto include : file.GetIncludes())
|
||||
{
|
||||
for (auto includeDir : includeDirs)
|
||||
path = includeDir + include;
|
||||
if (CanOpenFile(path))
|
||||
{
|
||||
std::string path(includeDir + include);
|
||||
if (CanOpenFile(path))
|
||||
{
|
||||
bool inserted = dependencies.insert(path).second;
|
||||
if (inserted)
|
||||
{
|
||||
filesToProcess.push(path);
|
||||
}
|
||||
break;
|
||||
}
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (extension == "s" || extension == "inc")
|
||||
{
|
||||
filesToProcess.push(initialPath);
|
||||
|
||||
while (!filesToProcess.empty())
|
||||
{
|
||||
AsmFile file(filesToProcess.front());
|
||||
|
||||
filesToProcess.pop();
|
||||
|
||||
IncDirectiveType incDirectiveType;
|
||||
std::string path;
|
||||
|
||||
while ((incDirectiveType = file.ReadUntilIncDirective(path)) != IncDirectiveType::None)
|
||||
if (!exists && (file.FileType() == SourceFileType::Asm || file.FileType() == SourceFileType::Inc))
|
||||
{
|
||||
bool inserted = dependencies.insert(path).second;
|
||||
if (inserted
|
||||
&& incDirectiveType == IncDirectiveType::Include
|
||||
&& CanOpenFile(path))
|
||||
filesToProcess.push(path);
|
||||
path = include;
|
||||
if (CanOpenFile(path))
|
||||
exists = true;
|
||||
}
|
||||
if (!exists)
|
||||
continue;
|
||||
|
||||
dependencies_includes.insert(path);
|
||||
bool inserted = dependencies.insert(path).second;
|
||||
if (inserted && exists)
|
||||
{
|
||||
filesToProcess.push(path);
|
||||
}
|
||||
}
|
||||
includeDirs.pop_back();
|
||||
}
|
||||
|
||||
if(!makeformat)
|
||||
{
|
||||
for (const std::string &path : dependencies)
|
||||
{
|
||||
std::printf("%s\n", path.c_str());
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
FATAL_ERROR("unknown extension \"%s\"\n", extension.c_str());
|
||||
}
|
||||
// Write out make rules to a file
|
||||
std::ofstream output(make_outfile);
|
||||
|
||||
for (const std::string &path : dependencies)
|
||||
{
|
||||
std::printf("%s\n", path.c_str());
|
||||
// Print a make rule for the object file
|
||||
size_t ext_pos = make_outfile.find_last_of(".");
|
||||
auto object_file = make_outfile.substr(0, ext_pos + 1) + "o";
|
||||
output << object_file.c_str() << ":";
|
||||
for (const std::string &path : dependencies)
|
||||
{
|
||||
output << " " << path;
|
||||
}
|
||||
output << '\n';
|
||||
|
||||
// Dependency list rule.
|
||||
// Although these rules are identical, they need to be separate, else make will trigger the rule again after the file is created for the first time.
|
||||
output << make_outfile.c_str() << ":";
|
||||
for (const std::string &path : dependencies_includes)
|
||||
{
|
||||
output << " " << path;
|
||||
}
|
||||
output << '\n';
|
||||
|
||||
// Dummy rules
|
||||
// If a dependency is deleted, make will try to make it, instead of rescanning the dependencies before trying to do that.
|
||||
for (const std::string &path : dependencies)
|
||||
{
|
||||
output << path << ":\n";
|
||||
}
|
||||
|
||||
output.flush();
|
||||
output.close();
|
||||
}
|
||||
}
|
||||
Vendored
+130
@@ -0,0 +1,130 @@
|
||||
// Copyright(c) 2019 Phlosioneer
|
||||
//
|
||||
// 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 <new>
|
||||
#include "source_file.h"
|
||||
|
||||
|
||||
SourceFileType GetFileType(std::string& path)
|
||||
{
|
||||
std::size_t pos = path.find_last_of('.');
|
||||
|
||||
if (pos == std::string::npos)
|
||||
FATAL_ERROR("no file extension in path \"%s\"\n", path.c_str());
|
||||
|
||||
std::string extension = path.substr(pos + 1);
|
||||
|
||||
if (extension == "c")
|
||||
return SourceFileType::Cpp;
|
||||
else if (extension == "s")
|
||||
return SourceFileType::Asm;
|
||||
else if (extension == "h")
|
||||
return SourceFileType::Header;
|
||||
else if (extension == "inc")
|
||||
return SourceFileType::Inc;
|
||||
else
|
||||
FATAL_ERROR("Unrecognized extension \"%s\"\n", extension.c_str());
|
||||
|
||||
// Unreachable
|
||||
return SourceFileType::Cpp;
|
||||
}
|
||||
|
||||
std::string GetDir(std::string& path)
|
||||
{
|
||||
std::size_t slash = path.rfind('/');
|
||||
|
||||
if (slash != std::string::npos)
|
||||
return path.substr(0, slash + 1);
|
||||
else
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
SourceFile::SourceFile(std::string path)
|
||||
{
|
||||
m_file_type = GetFileType(path);
|
||||
|
||||
m_src_dir = GetDir(path);
|
||||
|
||||
if (m_file_type == SourceFileType::Cpp
|
||||
|| m_file_type == SourceFileType::Header)
|
||||
{
|
||||
new (&m_source_file.c_file) CFile(path);
|
||||
m_source_file.c_file.FindIncbins();
|
||||
}
|
||||
else
|
||||
{
|
||||
AsmFile file(path);
|
||||
std::set<std::string> incbins;
|
||||
std::set<std::string> includes;
|
||||
|
||||
IncDirectiveType incDirectiveType;
|
||||
std::string outputPath;
|
||||
|
||||
while ((incDirectiveType = file.ReadUntilIncDirective(outputPath)) != IncDirectiveType::None)
|
||||
{
|
||||
if (incDirectiveType == IncDirectiveType::Include)
|
||||
includes.insert(outputPath);
|
||||
else
|
||||
incbins.insert(outputPath);
|
||||
}
|
||||
|
||||
new (&m_source_file.asm_wrapper) SourceFile::InnerUnion::AsmWrapper{incbins, includes};
|
||||
}
|
||||
}
|
||||
|
||||
SourceFileType SourceFile::FileType()
|
||||
{
|
||||
return m_file_type;
|
||||
}
|
||||
|
||||
SourceFile::~SourceFile()
|
||||
{
|
||||
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
|
||||
{
|
||||
m_source_file.c_file.~CFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_source_file.asm_wrapper.asm_incbins.~set();
|
||||
m_source_file.asm_wrapper.asm_includes.~set();
|
||||
}
|
||||
}
|
||||
|
||||
const std::set<std::string>& SourceFile::GetIncbins()
|
||||
{
|
||||
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
|
||||
return m_source_file.c_file.GetIncbins();
|
||||
else
|
||||
return m_source_file.asm_wrapper.asm_incbins;
|
||||
}
|
||||
|
||||
const std::set<std::string>& SourceFile::GetIncludes()
|
||||
{
|
||||
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
|
||||
return m_source_file.c_file.GetIncludes();
|
||||
else
|
||||
return m_source_file.asm_wrapper.asm_includes;
|
||||
}
|
||||
|
||||
std::string& SourceFile::GetSrcDir()
|
||||
{
|
||||
return m_src_dir;
|
||||
}
|
||||
|
||||
+40
-39
@@ -1,4 +1,4 @@
|
||||
// Copyright(c) 2016 YamaArashi
|
||||
// Copyright(c) 2019 Phlosioneer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -18,54 +18,55 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef SYM_FILE_H
|
||||
#define SYM_FILE_H
|
||||
#ifndef SOURCE_FILE_H
|
||||
#define SOURCE_FILE_H
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include "ramscrgen.h"
|
||||
#include "scaninc.h"
|
||||
#include "asm_file.h"
|
||||
#include "c_file.h"
|
||||
|
||||
enum class Directive
|
||||
enum class SourceFileType
|
||||
{
|
||||
Include,
|
||||
Space,
|
||||
Align,
|
||||
Unknown
|
||||
Cpp,
|
||||
Header,
|
||||
Asm,
|
||||
Inc
|
||||
};
|
||||
|
||||
class SymFile
|
||||
SourceFileType GetFileType(std::string& path);
|
||||
|
||||
class SourceFile
|
||||
{
|
||||
public:
|
||||
SymFile(std::string filename);
|
||||
SymFile(SymFile&& other);
|
||||
SymFile(const SymFile&) = delete;
|
||||
~SymFile();
|
||||
Directive GetDirective();
|
||||
std::string GetLabel(bool requireColon = true);
|
||||
std::string ReadPath();
|
||||
bool ReadInteger(unsigned long& value);
|
||||
void ExpectEmptyRestOfLine();
|
||||
void SkipLine();
|
||||
bool IsAtEnd();
|
||||
void HandleLangConditional(std::string lang);
|
||||
void RaiseError(const char* format, ...);
|
||||
void RaiseWarning(const char* format, ...);
|
||||
|
||||
SourceFile(std::string path);
|
||||
~SourceFile();
|
||||
SourceFile(SourceFile const&) = delete;
|
||||
SourceFile(SourceFile&&) = delete;
|
||||
SourceFile& operator =(SourceFile const&) = delete;
|
||||
SourceFile& operator =(SourceFile&&) = delete;
|
||||
bool HasIncbins();
|
||||
const std::set<std::string>& GetIncbins();
|
||||
const std::set<std::string>& GetIncludes();
|
||||
std::string& GetSrcDir();
|
||||
SourceFileType FileType();
|
||||
|
||||
private:
|
||||
char* m_buffer;
|
||||
long m_pos;
|
||||
long m_size;
|
||||
long m_lineNum;
|
||||
long m_lineStart;
|
||||
std::string m_filename;
|
||||
bool m_inLangConditional;
|
||||
union InnerUnion {
|
||||
CFile c_file;
|
||||
struct AsmWrapper {
|
||||
std::set<std::string> asm_incbins;
|
||||
std::set<std::string> asm_includes;
|
||||
} asm_wrapper;
|
||||
|
||||
bool ConsumeComma();
|
||||
void RemoveComments();
|
||||
bool CheckForDirective(std::string name);
|
||||
void SkipWhitespace();
|
||||
void ReportDiagnostic(const char* type, const char* format, std::va_list args);
|
||||
// Construction and destruction handled by SourceFile.
|
||||
InnerUnion() {};
|
||||
~InnerUnion() {};
|
||||
} m_source_file;
|
||||
SourceFileType m_file_type;
|
||||
std::string m_src_dir;
|
||||
};
|
||||
|
||||
#endif // SYM_FILE_H
|
||||
#endif // SOURCE_FILE_H
|
||||
|
||||
Reference in new issue
Block a user