Files
test/Assets/PerfectWorld/Scripts/Common/AWScriptFile.cs
T
2025-11-12 17:20:15 +07:00

260 lines
9.8 KiB
C#

using System;
using System.IO;
using ModelRenderer.Scripts.Common;
namespace BrewMonster.Common
{
public struct SCRIPTINFO
{
public byte[] pFileBuf; // Pointer to file data buffer
public byte[] pStart; // Start address of buffer
public byte[] pEnd; // End address of buffer
public byte[] pCur; // Current pointer. Pointer size is 2 bytes
public uint pCurIndex; // Current pointer index
public int iLine; // Line counter
}
public class AWScriptFile
{
private const int MAX_LINELEN = 2048;
public ushort[] m_szToken = new ushort[MAX_LINELEN];
protected SCRIPTINFO m_Script = new SCRIPTINFO();
public bool Open(FileStream stream)
{
uint dwFilelen = (uint)stream.Length;
if (dwFilelen <= 0)
{
BMLogger.LogError($"EC_StringTab::Open: {stream.Name} File length is 0");
return false;
}
byte[] pBuf = new byte[dwFilelen];
stream.Read(pBuf, 0, (int)dwFilelen);
// Check unicode file header
ushort wChar = BitConverter.ToUInt16(new byte[] {pBuf[0], pBuf[1]});
if (wChar != 0xfeff)
{
BMLogger.LogError($"EC_StringTab::Open: {stream.Name} File is not unicode");
return false;
}
m_Script.pFileBuf = pBuf;
m_Script.pStart = new []{m_Script.pFileBuf[2], m_Script.pFileBuf[3]}; // Skip unicode magic number
m_Script.pCur = m_Script.pStart;
m_Script.pEnd = new [] {m_Script.pFileBuf[pBuf.Length - 2], m_Script.pFileBuf[pBuf.Length - 1]};
m_Script.pCurIndex = 2;
m_Script.iLine = 0;
return true;
}
public bool Open(string szFile)
{
if (!File.Exists(szFile))
{
BMLogger.LogError($"EC_StringTab::Open: {szFile} File not found");
return false;
}
using (FileStream stream = new FileStream(szFile, FileMode.Open, FileAccess.Read))
{
var bRet = Open(stream);
if (!bRet)
{
BMLogger.LogError($"EC_StringTab::Open: {szFile} File open failed");
return false;
}
stream.Close();
return true;
}
}
public void Close()
{
//TODO: May be not needed
m_Script.pFileBuf = null;
m_Script.pStart = null;
m_Script.pCur = null;
m_Script.pEnd = null;
}
/// <summary>
/// Get next token and move file pointer forward.
/// </summary>
/// <param name="bCrossLine">true, search next token until it is found or all buffer has been checked;<br/> false, only search next token in current line</param>
/// <returns>true for success, otherwise return false</returns>
public bool GetNextToken(bool bCrossLine)
{
NewLine:
while (m_Script.pCurIndex < m_Script.pFileBuf.Length)
{
// get the first byte because the pointer is 2 bytes. The second byte should be 0 in these cases (value < 255)
if (m_Script.pFileBuf[m_Script.pCurIndex] > 32 && m_Script.pFileBuf[m_Script.pCurIndex] != ';' &&
m_Script.pFileBuf[m_Script.pCurIndex] != ',')
break;
m_Script.pCurIndex += 2; // move pointer forward 2 bytes because it's w_char (2 bytes)
if (m_Script.pCurIndex >= m_Script.pFileBuf.Length)
return false;
m_Script.pCur[0] = m_Script.pFileBuf[m_Script.pCurIndex];
m_Script.pCur[1] = m_Script.pFileBuf[m_Script.pCurIndex + 1];
if (m_Script.pCur[0] == '\n')
{
if (!bCrossLine)
{
m_Script.pCurIndex -= 2; // Let search pointer still stop in this line
return false;
}
m_Script.iLine++;
}
}
if (m_Script.pCurIndex >= m_Script.pFileBuf.Length)
return false;
// Skip comment lines those begin with '//'
if (m_Script.pFileBuf[m_Script.pCurIndex] == '/' && m_Script.pFileBuf[m_Script.pCurIndex + 2] == '/')
{
// This is a note line, search it's ending.
while (!m_Script.pCur.Equals(m_Script.pEnd) && m_Script.pFileBuf[m_Script.pCurIndex] != '\n')
{
m_Script.pCurIndex += 2;
}
if (m_Script.pCurIndex >= m_Script.pFileBuf.Length) // Found nothing
return false;
if (!bCrossLine) // Don't search cross line
return false;
m_Script.pCurIndex += 2; // Skip '\n'
m_Script.iLine++;
goto NewLine;
}
// Text between /* */ are also comment
if (m_Script.pFileBuf[m_Script.pCurIndex] == '/' && m_Script.pFileBuf[m_Script.pCurIndex + 2] == '*')
{
bool bError = false;
m_Script.pCurIndex += 4; // Skip /*
while (m_Script.pFileBuf[m_Script.pCurIndex] != '*' || m_Script.pFileBuf[m_Script.pCurIndex + 2] != '/')
{
if (m_Script.pCurIndex >= m_Script.pEnd.Length) // Found nothing
return false;
else if (m_Script.pFileBuf[m_Script.pCurIndex] == '\n')
{
if (!bCrossLine)
{
// This is a fatal error, we should return false.
// But we must search the '*/' so that next time our begin point
// isn't in comment paragraph
bError = true;
}
m_Script.iLine++;
}
m_Script.pCurIndex += 2;
}
m_Script.pCurIndex += 4; // Skip */
if (bError)
return false;
goto NewLine;
}
int i = 0;
// Copy string in "" or () pair
if (m_Script.pFileBuf[m_Script.pCurIndex] == '"' || m_Script.pFileBuf[m_Script.pCurIndex] == '(')
{
char cEnd = m_Script.pFileBuf[m_Script.pCurIndex] == '"' ? '"' : ')';
// Quoted token
m_Script.pCurIndex += 2; // Skip " or (
m_Script.pCur[0] = m_Script.pFileBuf[m_Script.pCurIndex];
m_Script.pCur[1] = m_Script.pFileBuf[m_Script.pCurIndex + 1];
while (!m_Script.pCur.Equals(m_Script.pEnd) && m_Script.pFileBuf[m_Script.pCurIndex] != cEnd)
{
if (i >= MAX_LINELEN-1)
return false;
// save the text into the token array
m_szToken[i++] = BitConverter.ToUInt16(m_Script.pCur);
m_Script.pCurIndex += 2;
m_Script.pCur[0] = m_Script.pFileBuf[m_Script.pCurIndex];
m_Script.pCur[1] = m_Script.pFileBuf[m_Script.pCurIndex + 1];
}
m_Script.pCurIndex += 2; // Skip " or )
m_Script.pCur[0] = m_Script.pFileBuf[m_Script.pCurIndex];
m_Script.pCur[1] = m_Script.pFileBuf[m_Script.pCurIndex + 1];
}
else // Is a normal token
{
while (!m_Script.pCur.Equals(m_Script.pEnd) && BitConverter.ToInt16(m_Script.pCur) > 32 &&
m_Script.pFileBuf[m_Script.pCurIndex] != ';' && m_Script.pFileBuf[m_Script.pCurIndex] != ',')
{
if (i >= MAX_LINELEN-1)
return false;
m_szToken[i++] = BitConverter.ToUInt16(m_Script.pCur);
m_Script.pCurIndex += 2;
m_Script.pCur[0] = m_Script.pFileBuf[m_Script.pCurIndex];
m_Script.pCur[1] = m_Script.pFileBuf[m_Script.pCurIndex + 1];
}
}
m_szToken[i] = '\0';
return true;
}
/// <summary>
/// Peek next token and don't move file pointer
/// Return true for success, otherwise return false
/// </summary>
/// <param name="bCrossLine">true, search next token until it is found or all buffer has been checked; false, only search next token in current line</param>
public bool PeekNextToken(bool bCrossLine)
{
// Record current pointer and line
var pCur = new [] {m_Script.pCur[0], m_Script.pCur[1]};
var iLine = m_Script.iLine;
var pCurIndex = m_Script.pCurIndex;
bool bRet = GetNextToken(bCrossLine);
// Restore pointer and line
m_Script.pCur = pCur;
m_Script.iLine = iLine;
m_Script.pCurIndex = pCurIndex;
return bRet;
}
public int GetNextTokenAsInt(bool bCrossLine)
{
GetNextToken(bCrossLine);
return int.Parse(ByteToStringUtils.UshortArrayToUnicodeString(m_szToken));
}
// Reach end of file ?
public bool IsEnd() { return m_Script.pCurIndex >= m_Script.pFileBuf.Length; }
// Get current line
public int GetCurLine() { return m_Script.iLine; }
}
}