|
From: <sag...@us...> - 2010-07-16 19:20:29
|
Revision: 648
http://modplug.svn.sourceforge.net/modplug/?rev=648&view=rev
Author: saga-games
Date: 2010-07-16 19:20:22 +0000 (Fri, 16 Jul 2010)
Log Message:
-----------
[Ref] Message reading: It's now possible to specify a callback function for converting characters. The AMS loader makes use of this.
Modified Paths:
--------------
trunk/OpenMPT/soundlib/Load_ams.cpp
trunk/OpenMPT/soundlib/Message.cpp
trunk/OpenMPT/soundlib/Sndfile.h
Modified: trunk/OpenMPT/soundlib/Load_ams.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Load_ams.cpp 2010-07-15 23:55:10 UTC (rev 647)
+++ trunk/OpenMPT/soundlib/Load_ams.cpp 2010-07-16 19:20:22 UTC (rev 648)
@@ -5,6 +5,12 @@
*
* Authors: Olivier Lapicque <oli...@jp...>
* OpenMPT dev(s) (miscellaneous modifications)
+ * Notes : Extreme was renamed to Velvet Development at some point,
+ * and thus they also renamed their tracker from
+ * "Extreme's Tracker" to "Velvet Studio".
+ * While the two programs look rather similiar, the structure of both
+ * programs' "AMS" format is significantly different - Velvet Studio is a
+ * rather advanced tracker in comparison to Extreme's Tracker.
*/
//////////////////////////////////////////////
@@ -44,7 +50,28 @@
#pragma pack()
+// Callback function for reading text
+void Convert_AMS_Text_Chars(char &c)
+//----------------------------------
+{
+ switch((unsigned char)c)
+ {
+ case 0x00:
+ case 0x81: c = ' '; break;
+ case 0x14: c = '\xF6'; break;
+ case 0x19: c = '\xD6'; break;
+ case 0x04: c = '\xE4'; break;
+ case 0x0E: c = '\xC4'; break;
+ case 0x06: c = '\xE5'; break;
+ case 0x0F: c = '\xC5'; break;
+ default:
+ if((unsigned char)c > 0x81)
+ c = '\r';
+ break;
+ }
+}
+
bool CSoundFile::ReadAMS(const LPCBYTE lpStream, const DWORD dwMemLength)
//-----------------------------------------------------------------------
{
@@ -136,29 +163,9 @@
tmp = *((WORD *)(lpStream+dwMemPos));
dwMemPos += 2;
if (dwMemPos + tmp >= dwMemLength) return true;
- if (tmp && AllocateMessage(tmp))
+ if (tmp)
{
- // Translate that weird text format...
- for(size_t i = 0; i < tmp; i++)
- {
- switch(lpStream[dwMemPos + i])
- {
- case 0x00:
- case 0x81: m_lpszSongComments[i] = ' '; break;
- case 0x14: m_lpszSongComments[i] = '\xF6'; break;
- case 0x19: m_lpszSongComments[i] = '\xD6'; break;
- case 0x04: m_lpszSongComments[i] = '\xE4'; break;
- case 0x0E: m_lpszSongComments[i] = '\xC4'; break;
- case 0x06: m_lpszSongComments[i] = '\xE5'; break;
- case 0x0F: m_lpszSongComments[i] = '\xC5'; break;
- default:
- if(lpStream[dwMemPos + i] > 0x81)
- m_lpszSongComments[i] = '\r';
- else
- m_lpszSongComments[i] = lpStream[dwMemPos + i];
- break;
- }
- }
+ ReadMessage(lpStream + dwMemPos, tmp, leCR, &Convert_AMS_Text_Chars);
}
dwMemPos += tmp;
@@ -352,11 +359,11 @@
BYTE packedsamples[MAX_SAMPLES];
if ((pfh->dwHdr1 != 0x68534D41) || (pfh->wHdr2 != 0x7264)
- || (pfh->b1A != 0x1A) || (pfh->titlelen > 30)) return FALSE;
+ || (pfh->b1A != 0x1A) || (pfh->titlelen > 30)) return false;
dwMemPos = pfh->titlelen + 8;
psh = (AMS2SONGHEADER *)(lpStream + dwMemPos);
if (((psh->version & 0xFF00) != 0x0200) || (!psh->instruments)
- || (psh->instruments > MAX_INSTRUMENTS) || (!psh->patterns) || (!psh->orders)) return FALSE;
+ || (psh->instruments > MAX_INSTRUMENTS) || (!psh->patterns) || (!psh->orders)) return false;
dwMemPos += sizeof(AMS2SONGHEADER);
if (pfh->titlelen)
{
@@ -461,7 +468,7 @@
dwMemPos += sizeof(AMS2SAMPLE);
}
}
- if (dwMemPos + 256 >= dwMemLength) return TRUE;
+ if (dwMemPos + 256 >= dwMemLength) return true;
// Comments
{
UINT composernamelen = lpStream[dwMemPos];
@@ -480,16 +487,16 @@
SpaceToNullStringFixed(ChnSettings[i].szName, chnnamlen);
}
dwMemPos += chnnamlen + 1;
- if (dwMemPos + chnnamlen + 256 >= dwMemLength) return TRUE;
+ if (dwMemPos + chnnamlen + 256 >= dwMemLength) return true;
}
// packed comments (ignored)
UINT songtextlen = *((LPDWORD)(lpStream+dwMemPos));
dwMemPos += songtextlen;
- if (dwMemPos + 256 >= dwMemLength) return TRUE;
+ if (dwMemPos + 256 >= dwMemLength) return true;
}
// Order List
{
- if ((dwMemPos + 2 * psh->orders) >= dwMemLength) return TRUE;
+ if ((dwMemPos + 2 * psh->orders) >= dwMemLength) return true;
Order.resize(psh->orders, Order.GetInvalidPatIndex());
for (UINT iOrd = 0; iOrd < psh->orders; iOrd++)
{
@@ -500,7 +507,7 @@
// Pattern Data
for (UINT ipat=0; ipat<psh->patterns; ipat++)
{
- if (dwMemPos+8 >= dwMemLength) return TRUE;
+ if (dwMemPos+8 >= dwMemLength) return true;
UINT packedlen = *((LPDWORD)(lpStream+dwMemPos));
UINT numrows = 1 + (UINT)(lpStream[dwMemPos+4]);
//UINT patchn = 1 + (UINT)(lpStream[dwMemPos+5] & 0x1F);
@@ -516,7 +523,7 @@
SpaceToNullStringFixed(s, patnamlen);
SetPatternName(ipat, s);
}
- if(Patterns.Insert(ipat, numrows)) return TRUE;
+ if(Patterns.Insert(ipat, numrows)) return true;
// Unpack Pattern Data
LPCBYTE psrc = lpStream + dwMemPos;
UINT pos = 3 + patnamlen;
@@ -570,7 +577,7 @@
// Read Samples
for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Samples[iSmp].nLength)
{
- if (dwMemPos >= dwMemLength - 9) return TRUE;
+ if (dwMemPos >= dwMemLength - 9) return true;
UINT flags;
if (packedsamples[iSmp] & 0x03)
{
@@ -581,7 +588,7 @@
}
dwMemPos += ReadSample(&Samples[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
}
- return TRUE;
+ return true;
}
Modified: trunk/OpenMPT/soundlib/Message.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Message.cpp 2010-07-15 23:55:10 UTC (rev 647)
+++ trunk/OpenMPT/soundlib/Message.cpp 2010-07-16 19:20:22 UTC (rev 648)
@@ -51,21 +51,30 @@
// [in] data: pointer to the data in memory that is going to be read
// [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended).
// [in] lineEnding: line ending formatting of the text in memory.
+// [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise).
// [out] returns true on success.
-bool CSoundFile::ReadMessage(const BYTE *data, const size_t length, enmLineEndings lineEnding)
-//--------------------------------------------------------------------------------------------
+bool CSoundFile::ReadMessage(const BYTE *data, const size_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &))
+//----------------------------------------------------------------------------------------------------------------------------
{
+ char c;
+
// Simple line-ending detection algorithm. VERY simple.
if(lineEnding == leAutodetect)
{
+ char cprev = 0;
size_t nCR = 0, nLF = 0, nCRLF = 0;
// find CRs, LFs and CRLFs
for(size_t i = 0; i < length; i++)
- {
- if(data[i] == '\r') nCR++;
- else if(data[i] == '\n') nLF++;
+ {
+ c = data[i];
+ if(pTextConverter != nullptr)
+ pTextConverter(c);
- if(i && data[i - 1] == '\r' && data[i] == '\n') nCRLF++;
+ if(c == '\r') nCR++;
+ else if(c == '\n') nLF++;
+
+ if(i && cprev == '\r' && c == '\n') nCRLF++;
+ cprev = c;
}
// evaluate findings
if(nCR == nLF && nCR == nCRLF)
@@ -82,7 +91,11 @@
// calculate the final amount of characters to be allocated.
for(size_t i = 0; i < length; i++)
{
- switch(data[i])
+ c = data[i];
+ if(pTextConverter != nullptr)
+ pTextConverter(c);
+
+ switch(c)
{
case '\r':
if(lineEnding != leLF) final_length++;
@@ -102,7 +115,11 @@
size_t cpos = 0;
for(size_t i = 0; i < length; i++, cpos++)
{
- switch(data[i])
+ c = data[i];
+ if(pTextConverter != nullptr)
+ pTextConverter(c);
+
+ switch(c)
{
case '\r':
if(lineEnding != leLF)
@@ -121,7 +138,7 @@
m_lpszSongComments[cpos] = ' ';
break;
default:
- m_lpszSongComments[cpos] = data[i];
+ m_lpszSongComments[cpos] = c;
break;
}
}
@@ -135,9 +152,10 @@
// [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended).
// [in] lineLength: The fixed length of a line.
// [in] lineEndingLength: The padding space between two fikxed lines. (there could for example be a null char after every line)
+// [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise).
// [out] returns true on success.
-bool CSoundFile::ReadFixedLineLengthMessage(const BYTE *data, const size_t length, const size_t lineLength, const size_t lineEndingLength)
-//----------------------------------------------------------------------------------------------------------------------------------------
+bool CSoundFile::ReadFixedLineLengthMessage(const BYTE *data, const size_t length, const size_t lineLength, const size_t lineEndingLength, void (*pTextConverter)(char &))
+//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
{
if(lineLength == 0)
return false;
@@ -155,6 +173,9 @@
// fix weird chars
for(size_t lpos = 0; lpos < lineLength; lpos++)
{
+ // Pre-process text
+ if(pTextConverter != nullptr) pTextConverter(m_lpszSongComments[cpos + lpos]);
+
switch(m_lpszSongComments[cpos + lpos])
{
case '\0':
Modified: trunk/OpenMPT/soundlib/Sndfile.h
===================================================================
--- trunk/OpenMPT/soundlib/Sndfile.h 2010-07-15 23:55:10 UTC (rev 647)
+++ trunk/OpenMPT/soundlib/Sndfile.h 2010-07-16 19:20:22 UTC (rev 648)
@@ -964,16 +964,18 @@
// [in] data: pointer to the data in memory that is going to be read
// [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended).
// [in] lineEnding: line ending formatting of the text in memory.
+ // [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise).
// [out] returns true on success.
- bool ReadMessage(const BYTE *data, const size_t length, enmLineEndings lineEnding);
+ bool ReadMessage(const BYTE *data, const size_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &) = nullptr);
// Read comments with fixed line length from a mapped file.
// [in] data: pointer to the data in memory that is going to be read
// [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended).
// [in] lineLength: The fixed length of a line.
// [in] lineEndingLength: The padding space between two fikxed lines. (there could for example be a null char after every line)
+ // [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise).
// [out] returns true on success.
- bool ReadFixedLineLengthMessage(const BYTE *data, const size_t length, const size_t lineLength, const size_t lineEndingLength);
+ bool ReadFixedLineLengthMessage(const BYTE *data, const size_t length, const size_t lineLength, const size_t lineEndingLength, void (*pTextConverter)(char &) = nullptr);
// Currently unused (and the code doesn't look very nice :)
UINT GetSongMessage(LPSTR s, UINT cbsize, UINT linesize=32);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|