ssc/sbdump/main.cs

686 lines
25 KiB
C#
Raw Normal View History

2015-12-31 12:27:03 +09:00
using arookas.IO.Binary;
using System;
using System.IO;
using System.Linq;
using System.Text;
2019-11-22 02:28:39 +09:00
using System.Collections.Generic;
2015-12-31 12:27:03 +09:00
namespace arookas {
class sbdump {
static CommandLineSettings sSettings;
static aBinaryReader sReader;
static TextWriter sWriter;
2016-03-02 16:11:40 +09:00
static uint sTextOffset, sDataOffset, sSymOffset;
static int sDataCount, sSymCount, sVarCount;
2015-12-31 12:27:03 +09:00
2016-03-02 16:01:52 +09:00
const string cTitle = "sbdump arookas";
2015-12-31 12:27:03 +09:00
static readonly string[] sSymbolTypes = { "builtin", "function", "var", };
static readonly string[] sCommandNames = {
"int", "flt", "str", "adr", "var", "nop", "inc", "dec",
"add", "sub", "mul", "div", "mod", "ass", "eq", "ne",
"gt", "lt", "ge", "le", "neg", "not", "and", "or",
"band", "bor", "shl", "shr", "call", "func", "mkfr", "mkds",
"ret", "ret0", "jne", "jmp", "pop", "int0", "int1", "end",
};
2019-11-22 02:28:39 +09:00
static int Main(string[] args) {
#if !DEBUG
2015-12-31 12:27:03 +09:00
try {
#endif
2019-11-22 02:28:39 +09:00
Console.WriteLine(cTitle);
ReadCommandLine(args);
Console.WriteLine("Opening input file...");
using (var sb = File.OpenRead(sSettings.Input))
{
CreateReader(sb);
Console.WriteLine("Creating output file...");
using (sWriter = File.CreateText(sSettings.Output))
{
ReadHeader();
if (sSettings.OutputSun)
{
WriteSun();
}
else
{
WritePreamble();
if (sSettings.OutputHeader)
{
WriteHeader();
}
if (sSettings.OutputText)
{
WriteText();
}
if (sSettings.OutputData)
{
WriteData();
}
if (sSettings.OutputSym)
{
WriteSym();
}
if (sSettings.OutputVars)
{
WriteVars();
}
}
Console.WriteLine("Closing output file...");
}
Console.WriteLine("Closing input file...");
}
2015-12-31 12:27:03 +09:00
Console.WriteLine("Done.");
#if !DEBUG
2015-12-31 12:27:03 +09:00
}
catch (Exception e) {
Console.WriteLine(e.Message);
return 1;
}
#endif
return 0;
2015-12-31 12:27:03 +09:00
}
2019-11-22 02:28:39 +09:00
static void ReadCommandLine(string[] args)
{
2015-12-31 12:27:03 +09:00
Console.WriteLine("Reading command line...");
sSettings = new CommandLineSettings(new aCommandLine(args));
2015-12-31 12:27:03 +09:00
}
static void CreateReader(Stream stream) {
Console.WriteLine("Creating binary reader...");
sReader = new aBinaryReader(stream, Endianness.Big, Encoding.GetEncoding(932));
}
static void WritePreamble() {
Console.WriteLine("Writing preamble...");
sWriter.WriteLine("# {0}", cTitle);
sWriter.WriteLine("# {0}", DateTime.Now);
sWriter.WriteLine("# {0}", Path.GetFileName(sSettings.Input));
sWriter.WriteLine();
}
static void ReadHeader() {
Console.WriteLine("Reading header...");
if (sReader.Read32() != 0x53504342u) { // 'SPCB'
throw new Exception("Invalid magic.");
}
sTextOffset = sReader.Read32();
sDataOffset = sReader.Read32();
sDataCount = sReader.ReadS32();
2016-03-02 16:11:40 +09:00
sSymOffset = sReader.Read32();
sSymCount = sReader.ReadS32();
sVarCount = sReader.ReadS32();
2015-12-31 12:27:03 +09:00
}
2019-11-22 02:28:39 +09:00
static void WriteHeader()
{
2015-12-31 12:27:03 +09:00
Console.WriteLine("Outputting header...");
sWriter.WriteLine("# Header information");
sWriter.WriteLine("# .text offset : {0:X8}", sTextOffset);
sWriter.WriteLine("# .data offset : {0:X8}", sDataOffset);
sWriter.WriteLine("# .data count : {0}", sDataCount);
2016-03-02 16:11:40 +09:00
sWriter.WriteLine("# .sym offset : {0:X8}", sSymOffset);
sWriter.WriteLine("# .sym count : {0}", sSymCount);
sWriter.WriteLine("# var count : {0}", sVarCount);
2015-12-31 12:27:03 +09:00
sWriter.WriteLine();
}
2019-11-22 02:28:39 +09:00
static void WriteText()
{
2015-12-31 12:27:03 +09:00
Console.WriteLine("Outputting .text...");
sWriter.WriteLine(".text");
WriteText(0u);
2016-03-02 16:11:40 +09:00
var symbols = new Symbol[sSymCount];
2019-11-22 02:28:39 +09:00
for (var i = 0; i < sSymCount; ++i)
{
2015-12-31 12:27:03 +09:00
symbols[i] = FetchSymbol(i);
}
2019-11-22 02:28:39 +09:00
foreach (var symbol in symbols.Where(i => i.Type == SymbolType.Function).OrderBy(i => i.Data))
{
2015-12-31 12:27:03 +09:00
sWriter.WriteLine("{0}: ", FetchSymbolName(symbol));
WriteText(symbol.Data);
}
}
static void WriteText(uint ofs) {
byte command;
sReader.Keep();
sReader.Goto(sTextOffset + ofs);
var maxofs = 0u;
2015-12-31 12:27:03 +09:00
do {
var pos = sReader.Position - sTextOffset;
command = sReader.Read8();
sWriter.Write(" {0:X8} {1}", pos, sCommandNames[command]);
var nextofs = 0u;
2015-12-31 12:27:03 +09:00
switch (command) {
case 0x00: sWriter.Write(" {0}", sReader.ReadS32()); break;
case 0x01: sWriter.Write(" {0}", sReader.ReadF32()); break;
case 0x02: {
var data = sReader.ReadS32();
var value = FetchDataValue(data);
sWriter.Write(" {0} # \"{1}\"", data, value.Replace("\n", "\\n"));
2015-12-31 12:27:03 +09:00
break;
}
case 0x03: sWriter.Write(" ${0:X8}", sReader.Read32()); break;
2016-01-23 15:15:50 +09:00
case 0x04: WriteVar(); break;
2022-01-26 21:47:34 +09:00
case 0x06: break;
case 0x07: break;
2015-12-31 12:27:03 +09:00
case 0x0D: {
sReader.Read8(); // TSpcInterp skips this byte
WriteVar();
break;
}
case 0x1C: {
var dest = sReader.Read32();
var args = sReader.ReadS32();
var symbol = FetchSymbol(i => i.Data == dest);
if (symbol != null) {
sWriter.Write(" {0}, {1}", FetchSymbolName(symbol), args);
}
else {
sWriter.Write(" ${0:X8}, {1}", dest, args);
}
break;
}
case 0x1D: sWriter.Write(" {0}, {1}", FetchSymbolName(FetchSymbol(sReader.ReadS32())), sReader.ReadS32()); break;
case 0x1E: sWriter.Write(" {0}", sReader.ReadS32()); break;
case 0x1F: sWriter.Write(" {0}", sReader.ReadS32()); break;
case 0x22: nextofs = WriteJmp(ofs); break;
case 0x23: nextofs = WriteJmp(ofs); break;
2015-12-31 12:27:03 +09:00
}
sWriter.WriteLine();
if (nextofs > maxofs) {
maxofs = nextofs;
}
} while (!IsReturnCommand(command) || sReader.Position <= sTextOffset + maxofs);
2015-12-31 12:27:03 +09:00
sWriter.WriteLine();
sReader.Back();
}
static void WriteVar() {
var display = sReader.ReadS32();
var data = sReader.ReadS32();
sWriter.Write(" {0} {1}", display, data);
2015-12-31 12:27:03 +09:00
switch (display) {
case 0: sWriter.Write(" # {0}", FetchSymbolName(FetchSymbol(i => i.Type == SymbolType.Variable && i.Data == data))); break;
case 1: sWriter.Write(" # local{0}", data); break;
2015-12-31 12:27:03 +09:00
}
}
2016-02-01 18:41:06 +09:00
static uint WriteJmp(uint ofs) {
2015-12-31 12:27:03 +09:00
var dest = sReader.Read32();
var symbol = FetchSymbol(i => i.Data == ofs);
if (ofs > 0 && symbol != null) {
var name = FetchSymbolName(symbol);
2016-01-23 15:36:27 +09:00
sWriter.Write(" {0} + ${1:X4} # ${2:X8}", name, dest - ofs, dest);
2015-12-31 12:27:03 +09:00
}
else {
sWriter.Write(" ${0:X8}", dest);
}
2016-02-01 18:41:06 +09:00
return dest;
2015-12-31 12:27:03 +09:00
}
static void WriteData() {
Console.WriteLine("Outputting .data...");
sWriter.WriteLine(".data");
sReader.Goto(sDataOffset);
2016-03-02 16:45:06 +09:00
for (var i = 0; i < sDataCount; ++i) {
2015-12-31 12:27:03 +09:00
var ofs = sReader.Read32();
var data = FetchDataValue(ofs);
sWriter.WriteLine(" .string \"{0}\"", data.Replace("\n", "\\n"));
2015-12-31 12:27:03 +09:00
}
sWriter.WriteLine();
}
static void WriteSym() {
Console.WriteLine("Outputting .sym...");
sWriter.WriteLine(".sym");
2016-03-02 16:11:40 +09:00
sReader.Goto(sSymOffset);
2016-03-02 16:45:06 +09:00
for (var i = 0; i < sSymCount; ++i) {
2015-12-31 12:27:03 +09:00
var symbol = new Symbol(sReader);
var name = FetchSymbolName(symbol);
sWriter.WriteLine(" .{0} {1}", sSymbolTypes[(int)symbol.Type], name);
}
sWriter.WriteLine();
}
2016-03-02 16:44:47 +09:00
static void WriteVars() {
Console.WriteLine("Outputting variables...");
sWriter.WriteLine("# variables:");
2016-03-02 16:45:06 +09:00
for (var i = 0; i < sVarCount; ++i) {
2015-12-31 12:27:03 +09:00
var symbol = FetchSymbol(j => j.Type == SymbolType.Variable && j.Data == i);
if (symbol != null) {
2016-03-02 16:44:47 +09:00
sWriter.WriteLine("# {0}", FetchSymbolName(symbol));
2015-12-31 12:27:03 +09:00
}
else {
2016-03-02 16:44:47 +09:00
sWriter.WriteLine("# (NULL)");
2015-12-31 12:27:03 +09:00
}
}
sWriter.WriteLine();
}
2019-11-22 02:28:39 +09:00
static void WriteSun()
{
Console.WriteLine("Decompiling sb file...");
2019-11-22 02:28:39 +09:00
var symbols = new Symbol[sSymCount];
for (var i = 0; i < sSymCount; ++i)
{
symbols[i] = FetchSymbol(i);
}
foreach (var symbol in symbols.Where(i => i.Type == SymbolType.Function).OrderBy(i => i.Data))
{
sWriter.WriteLine();
sWriter.WriteLine("function "+ FetchSymbolName(symbol)+ "(...)" + Environment.NewLine+ "{");
DecompFunction(symbol.Data, 1);
sWriter.WriteLine("}");
sWriter.WriteLine();
}
DecompFunction(0u, 0);//Decompile main part.
2019-11-22 02:28:39 +09:00
}
static void DecompFunction(uint ofs, int IndentL)
2019-11-22 02:28:39 +09:00
{
byte command;
sReader.Keep();
sReader.Goto(sTextOffset + ofs);
var maxofs = 0u;
Stack<string> Stack = new Stack<string>();
CodeGraph FuncCodeGraph = new CodeGraph();
HashSet<string> DeclaredTable = new HashSet<string>();
2019-11-22 02:28:39 +09:00
do
{
var pos = sReader.Position - sTextOffset;
command = sReader.Read8();
var nextofs = 0u;
switch (command)
{
case 0x00: //int
{
Stack.Push(sReader.ReadS32().ToString());
break;
}
case 0x01: //flt
{
2022-01-26 21:47:34 +09:00
Stack.Push(sReader.ReadF32().ToString("0.0###############"));
2019-11-22 02:28:39 +09:00
break;
}
case 0x02: //str
{
var data = sReader.ReadS32();
var value = FetchDataValue(data);
2022-01-26 21:47:34 +09:00
Stack.Push("\"" + value.Replace("\n", "\\n") +"\"");
2019-11-22 02:28:39 +09:00
break;
}
case 0x03: //adr
{
2022-01-26 21:47:34 +09:00
Stack.Push("$" + sReader.ReadS32().ToString("X8"));
2019-11-22 02:28:39 +09:00
break;
}
case 0x04: //var
{
var display = sReader.ReadS32();
var data = sReader.ReadS32();
switch (display)
{
case 0: Stack.Push(FetchSymbolName(FetchSymbol(i => i.Type == SymbolType.Variable && i.Data == data))); break;
2022-01-26 21:47:34 +09:00
case 1: Stack.Push("local " + data.ToString()); break;
2019-11-22 02:28:39 +09:00
}
break;
}
case 0x06: //inc
{
2022-01-26 21:47:34 +09:00
sReader.ReadS8(); // Ignore inline var
var display = sReader.ReadS32();
var data = sReader.ReadS32();
switch (display)
{
case 0: Stack.Push("++" + FetchSymbolName(FetchSymbol(i => i.Type == SymbolType.Variable && i.Data == data))); break;
case 1: Stack.Push("++" + data.ToString()); break;
}
2019-11-22 02:28:39 +09:00
break;
}
case 0x07: //dec
{
2022-01-26 21:47:34 +09:00
sReader.ReadS8(); // Ignore inline var
var display = sReader.ReadS32();
var data = sReader.ReadS32();
switch (display)
{
case 0: Stack.Push("--" + FetchSymbolName(FetchSymbol(i => i.Type == SymbolType.Variable && i.Data == data))); break;
case 1: Stack.Push("--" + data.ToString()); break;
}
2019-11-22 02:28:39 +09:00
break;
}
case 0x08: //add
{
string Op2 = Stack.Pop();
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " + " + Op2 + ")");
break;
}
case 0x09: //sub
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " - " + Op2 + ")");
break;
}
case 0x0A: //mul
{
string Op2 = Stack.Pop();
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " * " + Op2 + ")");
break;
}
case 0x0B: //div
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " / " + Op2 + ")");
break;
}
case 0x0C: //mod
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " % " + Op2 + ")");
break;
}
case 0x0D: //ass
{
sReader.Read8(); //Ignore this byte
var display = sReader.ReadS32();
var data = sReader.ReadS32();
string VariableName = "";
switch (display)
{
case 0:
{
VariableName = FetchSymbolName(FetchSymbol(i => i.Type == SymbolType.Variable && i.Data == data));
if (!DeclaredTable.Contains(VariableName))
{
DeclaredTable.Add(VariableName);
VariableName = "var " + VariableName;
}
break;
}
case 1:
{
VariableName = data.ToString();
if (!DeclaredTable.Contains(VariableName))
{
DeclaredTable.Add(VariableName);
VariableName = "var local " + VariableName;
}
break;
}
2019-11-22 02:28:39 +09:00
}
CodeVertex NewLine = new CodeVertex(VertexType.CodeBlock , -1, VariableName + " = " + Stack.Pop() + ";", pos);
FuncCodeGraph.AddVertex(NewLine);
2019-11-22 02:28:39 +09:00
break;
}
case 0x0E: //eq
{
string Op2 = Stack.Pop();
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " == " + Op2 + ")");
break;
}
case 0x0F: //ne
{
string Op2 = Stack.Pop();
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " != " + Op2 + ")");
break;
}
case 0x10: //gt
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " > " + Op2 + ")");
break;
}
case 0x11: //lt
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " < " + Op2 + ")");
break;
}
case 0x12: //ge
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " >= " + Op2 + ")");
break;
}
case 0x13: //le
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " <= " + Op2 + ")");
break;
}
case 0x14: //neg
{
string Op1 = Stack.Pop();
Stack.Push("-(" + Op1 + ")");
break;
}
case 0x15: //not
{
string Op1 = Stack.Pop();
Stack.Push("!(" + Op1 + ")");
break;
}
case 0x16: //and
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " && " + Op2 + ")");
break;
}
case 0x17: //or
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " || " + Op2 + ")");
break;
}
case 0x18: //band
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " & " + Op2 + ")");
break;
}
case 0x19: //bor
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " ^ " + Op2 + ")");
break;
}
case 0x1A: //shl
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " << " + Op2 + ")");
break;
}
case 0x1B: //shr
{
string Op2 = Stack.Pop();
2022-01-26 21:47:34 +09:00
string Op1 = Stack.Pop();
2019-11-22 02:28:39 +09:00
Stack.Push("(" + Op1 + " >> " + Op2 + ")");
break;
}
case 0x1C: //call
{
var dest = sReader.Read32();
var args = sReader.ReadS32();
var symbol = FetchSymbol(i => i.Data == dest);
string FuncName = "";
if (symbol != null)
{
FuncName = FetchSymbolName(symbol);
}
else
{
FuncName = dest.ToString("X8");
}
string FuncInput = "";
for(int i = 0; i < args; i++)
{
string Op = Stack.Pop();
if (i != 0)
FuncInput = Op + "," + FuncInput;
else
FuncInput = Op;
}
Stack.Push(FuncName + "(" + FuncInput + ")");
break;
}
case 0x1D: //func
{
string FuncName = FetchSymbolName(FetchSymbol(sReader.ReadS32()));
var args = sReader.ReadS32();
string FuncInput = "";
for (int i = 0; i < args; i++)
{
string Op = Stack.Pop();
if (i != 0)
FuncInput = Op + "," + FuncInput;
else
FuncInput = Op;
}
Stack.Push(FuncName + "(" + FuncInput + ")");
break;
}
case 0x1E: sReader.ReadS32(); break;
case 0x1F: sReader.ReadS32(); break;
case 0x20: //ret
{
string Op = Stack.Pop();
CodeVertex NewLine = new CodeVertex(VertexType.CodeBlock , -1, "return " + Op + ";", pos);
FuncCodeGraph.AddVertex(NewLine);
2019-11-22 02:28:39 +09:00
break;
}
case 0x21: //ret0
{
CodeVertex NewLine = new CodeVertex(VertexType.CodeBlock, -1, "return 0;", pos);
FuncCodeGraph.AddVertex(NewLine);
2019-11-22 02:28:39 +09:00
break;
}
case 0x22: //jne
{
var dest = sReader.Read32();
nextofs = dest;
string Op = Stack.Pop();
CodeVertex NewLine = new CodeVertex(VertexType.ConditionalBranch, dest, Op, pos);
FuncCodeGraph.AddVertex(NewLine);
2019-11-22 02:28:39 +09:00
break;
}
case 0x23: //jmp
{
var dest = sReader.Read32();
nextofs = dest;
CodeVertex NewLine = new CodeVertex(VertexType.Branch, dest, "", pos);
FuncCodeGraph.AddVertex(NewLine);
2019-11-22 02:28:39 +09:00
break;
}
case 0x24: //pop
{
string Op = Stack.Pop();
CodeVertex NewLine = new CodeVertex(VertexType.CodeBlock, -1, Op + ";", pos);
FuncCodeGraph.AddVertex(NewLine);
2019-11-22 02:28:39 +09:00
break;
}
case 0x25: //int0
{
Stack.Push("0");
break;
}
case 0x26: //int1
{
Stack.Push("1");
break;
}
}
if (nextofs > maxofs)
{
maxofs = nextofs;
}
} while (!IsReturnCommand(command) || sReader.Position <= sTextOffset + maxofs);
WriteCode(FuncCodeGraph, IndentL);
2019-11-22 02:28:39 +09:00
sWriter.WriteLine();
sReader.Back();
}
static void WriteCode(CodeGraph FuncCodeGraph, int Indent)
2019-11-22 02:28:39 +09:00
{
sWriter.Write(FuncCodeGraph.OutputCode(Indent));
2019-11-22 02:28:39 +09:00
}
static uint FetchData(int i) {
2015-12-31 12:27:03 +09:00
sReader.Keep();
sReader.Goto(sDataOffset + (4 * i));
var data = sReader.Read32();
sReader.Back();
return data;
}
static string FetchDataValue(int i) {
if (i < 0 || i >= sDataCount) {
2016-03-02 16:44:47 +09:00
return "(NULL)";
2015-12-31 12:27:03 +09:00
}
return FetchDataValue(FetchData(i));
}
static string FetchDataValue(uint ofs) {
sReader.Keep();
sReader.Goto(sDataOffset + (4 * sDataCount) + ofs);
var data = sReader.ReadString<aZSTR>();
2015-12-31 12:27:03 +09:00
sReader.Back();
return data;
}
static Symbol FetchSymbol(int i) {
sReader.Keep();
2016-03-02 16:11:40 +09:00
sReader.Goto(sSymOffset + (20 * i));
2015-12-31 12:27:03 +09:00
var symbol = new Symbol(sReader);
sReader.Back();
return symbol;
}
static Symbol FetchSymbol(Predicate<Symbol> predicate) {
if (predicate == null) {
throw new ArgumentNullException("predicate");
}
Symbol found = null;
sReader.Keep();
2016-03-02 16:11:40 +09:00
sReader.Goto(sSymOffset);
2016-03-02 16:45:06 +09:00
for (var i = 0; i < sSymCount; ++i) {
2015-12-31 12:27:03 +09:00
var symbol = new Symbol(sReader);
if (predicate(symbol)) {
found = symbol;
break;
}
}
sReader.Back();
return found;
}
static string FetchSymbolName(Symbol symbol) {
sReader.Keep();
2016-03-02 16:11:40 +09:00
sReader.Goto(sSymOffset + (20 * sSymCount) + symbol.StringOffset);
var name = sReader.ReadString<aZSTR>();
2015-12-31 12:27:03 +09:00
sReader.Back();
return name;
}
static bool IsReturnCommand(byte cmd) {
return (
cmd == 0x20 || // ret
cmd == 0x21 || // ret0
cmd == 0x27 // end
);
}
2015-12-31 12:27:03 +09:00
}
}