2002-07-23 01:41:40 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
Class: MsdFile
|
|
|
|
|
|
|
|
|
|
Desc: See header.
|
|
|
|
|
|
|
|
|
|
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
|
|
|
|
|
Chris Danford
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
2002-12-14 03:47:05 +00:00
|
|
|
/* The original MSD format is simply:
|
|
|
|
|
*
|
|
|
|
|
* #PARAM0:PARAM1:PARAM2:PARAM3;
|
|
|
|
|
* #NEXTPARAM0:PARAM1:PARAM2:PARAM3;
|
|
|
|
|
*
|
|
|
|
|
* (The first field is typically an identifier, but doesn't have to be.)
|
|
|
|
|
*
|
|
|
|
|
* The semicolon is not optional, though if we hit a # on a new line, eg:
|
|
|
|
|
* #VALUE:PARAM1
|
|
|
|
|
* #VALUE2:PARAM2
|
|
|
|
|
* we'll recover.
|
|
|
|
|
*
|
|
|
|
|
* Extension: If : is followed by ASCII 1 (^A), we read a binary value, in this
|
|
|
|
|
* form:
|
|
|
|
|
*
|
|
|
|
|
* #VALUE:^A4,DATA:more tags;
|
|
|
|
|
* "4" is the number of bytes of data to expect, not including itself, and not
|
|
|
|
|
* including the comma separating it from the data. The data is completely unparsed
|
|
|
|
|
* and may contain colons, #, or whitespace without fear of corruption. The ^A
|
|
|
|
|
* character is used to avoid it showing up in real data. We only use this internally
|
|
|
|
|
* for caching; this is ugly, so don't use it in distributed data!
|
|
|
|
|
*
|
|
|
|
|
* TODO: Normal text fields need some way of escaping. We need to be able to escape
|
|
|
|
|
* colons and "//". Also, we should escape #s, so if we really want to put a # at the
|
|
|
|
|
* beginning of a line, we can.
|
|
|
|
|
*/
|
2002-07-23 01:41:40 +00:00
|
|
|
#include "MsdFile.h"
|
2002-12-14 03:47:05 +00:00
|
|
|
#include "RageLog.h"
|
2002-10-05 14:47:03 +00:00
|
|
|
#include "io.h"
|
|
|
|
|
#include "fcntl.h"
|
2002-07-23 01:41:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
MsdFile::MsdFile()
|
|
|
|
|
{
|
2002-08-27 20:25:51 +00:00
|
|
|
m_iNumValues = 0;
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MsdFile::~MsdFile()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2002-12-14 03:47:05 +00:00
|
|
|
void MsdFile::AddParam( char *buf, int len )
|
2002-07-23 01:41:40 +00:00
|
|
|
{
|
2002-12-14 03:47:05 +00:00
|
|
|
int valueno = m_iNumValues-1;
|
|
|
|
|
int paramno = m_iNumParams[valueno];
|
|
|
|
|
ASSERT( paramno < MAX_PARAMS_PER_VALUE );
|
|
|
|
|
m_iNumParams[valueno]++;
|
2003-01-03 05:29:45 +00:00
|
|
|
m_sParams[valueno][paramno] = CString(buf, len);
|
2002-12-14 03:47:05 +00:00
|
|
|
}
|
2002-09-18 20:22:24 +00:00
|
|
|
|
2002-12-14 03:47:05 +00:00
|
|
|
void MsdFile::AddValue() /* (no extra charge) */
|
|
|
|
|
{
|
|
|
|
|
m_iNumValues++;
|
|
|
|
|
ASSERT( m_iNumValues < MAX_VALUES );
|
|
|
|
|
}
|
2002-07-23 01:41:40 +00:00
|
|
|
|
2002-12-14 03:47:05 +00:00
|
|
|
void MsdFile::ReadBuf( char *buf, int len )
|
|
|
|
|
{
|
|
|
|
|
int value_start = -1;
|
|
|
|
|
memset(m_iNumParams, 0, sizeof(m_iNumParams));
|
2002-07-23 01:41:40 +00:00
|
|
|
m_iNumValues = 0;
|
2002-08-20 01:27:42 +00:00
|
|
|
|
2002-08-30 05:05:34 +00:00
|
|
|
bool ReadingValue=false;
|
2002-12-14 03:47:05 +00:00
|
|
|
int i = 0;
|
|
|
|
|
while(i < len)
|
2002-07-23 01:41:40 +00:00
|
|
|
{
|
2002-12-14 03:47:05 +00:00
|
|
|
if(!strncmp(buf+i, "//", 2))
|
2002-07-23 01:41:40 +00:00
|
|
|
{
|
2002-12-14 03:47:05 +00:00
|
|
|
/* //; erase with spaces until newline */
|
|
|
|
|
do {
|
|
|
|
|
buf[i] = ' ';
|
|
|
|
|
i++;
|
|
|
|
|
} while(buf[i] != '\n');
|
2002-08-30 05:05:34 +00:00
|
|
|
|
2002-12-14 03:47:05 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!ReadingValue) {
|
|
|
|
|
// fast forward until the next '#' (optimization)
|
|
|
|
|
while(i < len && buf[i] != '#') i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(ReadingValue && buf[i] == '#') {
|
|
|
|
|
/* Unfortunately, many of these files are missing ;'s.
|
|
|
|
|
* If we get a # when we thought we were inside a value, assume we
|
|
|
|
|
* missed the ;. Back up and end the value. */
|
|
|
|
|
/* Make sure this # is the first non-whitespace character on the line. */
|
|
|
|
|
bool FirstChar = true;
|
|
|
|
|
int j;
|
|
|
|
|
for(j = i-1; j >= 0 && !strchr("\r\n", buf[j]); --j)
|
2002-07-23 01:41:40 +00:00
|
|
|
{
|
2002-12-14 03:47:05 +00:00
|
|
|
if(buf[j] == ' ' || buf[j] == '\t')
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
FirstChar = false;
|
|
|
|
|
break;
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
2002-12-14 03:47:05 +00:00
|
|
|
|
|
|
|
|
if(!FirstChar) {
|
|
|
|
|
/* Oops, we're not; handle this like a regular character. */
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
2002-12-14 03:47:05 +00:00
|
|
|
|
|
|
|
|
AddParam(buf+value_start, j - value_start);
|
|
|
|
|
ReadingValue=false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* # starts a new value. */
|
|
|
|
|
if(!ReadingValue && buf[i] == '#') {
|
|
|
|
|
AddValue();
|
|
|
|
|
ReadingValue=true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!ReadingValue)
|
|
|
|
|
{
|
|
|
|
|
i++;
|
|
|
|
|
continue; /* nothing else is meaningful outside of a value */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* : and ; end the current param, if any. */
|
|
|
|
|
if(value_start != -1 && (buf[i] == ':' || buf[i] == ';'))
|
|
|
|
|
AddParam(buf+value_start, i - value_start);
|
|
|
|
|
|
|
|
|
|
/* # and : begin new params. */
|
|
|
|
|
if(buf[i] == '#' || buf[i] == ':')
|
|
|
|
|
{
|
|
|
|
|
i++; /* skip */
|
|
|
|
|
value_start = i;
|
|
|
|
|
continue;
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
2002-12-14 03:47:05 +00:00
|
|
|
/* ; ends the current value. */
|
|
|
|
|
if(buf[i] == ';')
|
|
|
|
|
ReadingValue=false;
|
|
|
|
|
|
|
|
|
|
i++;
|
2002-07-23 01:41:40 +00:00
|
|
|
}
|
2002-12-14 21:30:24 +00:00
|
|
|
|
|
|
|
|
/* Add any unterminated value at the very end. */
|
|
|
|
|
if(ReadingValue)
|
|
|
|
|
AddParam(buf+value_start, i - value_start);
|
2002-12-14 03:47:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// returns true if successful, false otherwise
|
|
|
|
|
bool MsdFile::ReadFile( CString sNewPath )
|
|
|
|
|
{
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
/* Open a file */
|
|
|
|
|
if( (fd = open(sNewPath, _O_RDONLY, 0)) == -1 )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
int iBufferSize = _filelength( fd ) + 1000; // +1000 because sometimes the bytes read is > filelength. Why?
|
|
|
|
|
|
|
|
|
|
// allocate a string to hold the file
|
|
|
|
|
char* szFileString = new char[iBufferSize];
|
|
|
|
|
|
|
|
|
|
int iBytesRead = read( fd, szFileString, iBufferSize );
|
|
|
|
|
close( fd );
|
|
|
|
|
|
|
|
|
|
ASSERT( iBufferSize > iBytesRead );
|
|
|
|
|
szFileString[iBytesRead] = '\0';
|
|
|
|
|
|
|
|
|
|
ReadBuf(szFileString, iBytesRead);
|
2002-07-23 01:41:40 +00:00
|
|
|
|
2002-09-15 07:03:32 +00:00
|
|
|
delete [] szFileString;
|
2002-07-23 01:41:40 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|