Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,177 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "bagel/boflib/cache.h"
#include "bagel/boflib/log.h"
#include "bagel/spacebar/boflib/debug.h"
#include "bagel/boflib/misc.h"
namespace Bagel {
// Static members
CCache *CCache::_pCacheList;
uint32 CCache::_lOldest;
uint32 CCache::_lYoungest;
uint16 CCache::_nEntries;
void CCache::initialize() {
_pCacheList = nullptr;
_lOldest = 0xFFFFFFFF;
_lYoungest = 0xFFFFFFFF;
_nEntries = 0;
}
CCache::CCache() {
_bValid = true;
// Inits
_lAge = _lYoungest;
_bCached = false;
_nLockCount = 0;
if (_pCacheList == nullptr) {
// There can't be any other entries
assert(_nEntries == 0);
// This object is the start of the cache list
_pCacheList = this;
} else {
assert(_nEntries != 0);
_pCacheList->Insert(this);
}
// One more cached entry
_nEntries++;
}
CCache::~CCache() {
// Make sure this object is not deleted twice
assert(_bValid);
// There can be only one cache list per EXE/DLL
assert(this->getHead() == _pCacheList);
// Object must be released by the derived class destructor
assert(_bCached == false);
_nEntries--;
// Remove this object from the linked list
if (this == _pCacheList) {
_pCacheList = (CCache *)this->getNext();
}
this->Delete();
if (_nEntries == 0) {
_pCacheList = nullptr;
}
_bValid = false;
}
bool CCache::flush() {
bool bReleased = false;
CCache *pCache = _pCacheList;
while (pCache != nullptr) {
if (pCache->release())
bReleased = true;
pCache = (CCache *)(pCache->getNext());
}
return bReleased;
}
bool CCache::optimize(uint32 lRequestedFreeSpace) {
logInfo(buildString("CCache::optimize(%u)", lRequestedFreeSpace));
bool bSuccess = true;
while (getFreePhysMem() < lRequestedFreeSpace) {
uint32 lAvgAge = ((_lOldest - _lYoungest) / 2) + _lYoungest;
_lOldest = lAvgAge;
// Parse Linked list of cached objects and remove any that are too old
CCache *pCache = _pCacheList;
int nObjects = 0;
while (pCache != nullptr) {
if (pCache->_bCached && (pCache->_nLockCount <= 0)) {
nObjects++;
if (pCache->_lAge >= lAvgAge) {
logInfo(buildString("Freeing Object: %p from the Cache list", pCache));
pCache->release();
}
}
// Next object in list
pCache = (CCache *)pCache->getNext();
}
// If there are no objects loaded then we really might be out of memory
if (nObjects == 0) {
bSuccess = false;
break;
}
}
return bSuccess;
}
void CCache::load() {
// Make sure this object is not used after it is destructed
assert(_bValid);
// Timestamp this object
_lAge = --_lYoungest;
// If this object is not already cached
if (!_bCached) {
// We must tell the Cache library that this object is in the cache to avoid recursion
_bCached = true;
// Call the routine that will allocate the memory for this object
// alloc() is pure-virtual and must be defined in the derived class.
_bCached = alloc();
}
}
bool CCache::release() {
// Make sure this object is not used after it is destructed
assert(_bValid);
// If this object is in the cache
bool bReleased = false;
if (_bCached) {
bReleased = true;
// Call the routine that will free the memory used by this object.
// free() is pure-virtual and must be defined in the derived class.
free();
_bCached = false;
}
return bReleased;
}
} // namespace Bagel

View File

@@ -0,0 +1,101 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_CACHE_H
#define BAGEL_BOFLIB_CACHE_H
#include "bagel/boflib/llist.h"
#include "bagel/boflib/stdinc.h"
namespace Bagel {
class CCache : private CLList {
private:
virtual bool alloc() = 0; // These pure-virtuals MUST be defined
virtual void free() = 0; // in the derived class.
static CCache *_pCacheList; // Linked cache list
static uint32 _lOldest; // Current oldest object in cache
static uint32 _lYoungest; // Current youngest object in cache
static uint16 _nEntries; // Number of CCache Objects
uint32 _lAge; // Age of this object
int _nLockCount; // # of locks held on this object
bool _bCached; // true if object is in the cache
bool _bValid; // true if this object is valid
public:
/**
* Constructor
*/
CCache();
/**
* Destructor
*/
virtual ~CCache();
/**
* Loads current object into cache
*/
void load();
/**
* Releases current object from cache
*/
bool release();
void lock() {
_nLockCount++;
load();
}
void unlock() {
_nLockCount--;
}
bool isLocked() {
return (_nLockCount > 0);
}
/**
* initialize statics
*/
static void initialize();
/**
* Releases all objects from cache
*/
static bool flush();
/**
* Releases older objects from cache if need memory
* @remarks Optimizes cache so that the specified amount of memory is left available.
* @param lRequestedFreeSpace Free space requested to remain available
* @return true if there were any objects to release from the cache.
* false if there were no objects released.
*/
static bool optimize(uint32 lRequestedFreeSpace);
};
} // namespace Bagel
#endif

View File

@@ -0,0 +1,50 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "bagel/boflib/cursor_data.h"
namespace Bagel {
const byte ARROW_CURSOR[CURSOR_W * CURSOR_H] = {
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0,
1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0,
1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
1, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
1, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0,
1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0,
1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0, 0,
1, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0,
1, 2, 1, 0, 0, 1, 2, 2, 1, 0, 0, 0,
1, 1, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0,
1, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0,
0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
};
const byte CURSOR_PALETTE[9] = { 0x80, 0x80, 0x80, 0, 0, 0, 0xff, 0xff, 0xff };
} // namespace Bagel

View File

@@ -0,0 +1,38 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_CURSOR_DATA_H
#define BAGEL_BOFLIB_CURSOR_DATA_H
#include "common/scummsys.h"
namespace Bagel {
constexpr int CURSOR_W = 12;
constexpr int CURSOR_H = 20;
extern const byte ARROW_CURSOR[CURSOR_W * CURSOR_H];
extern const byte CURSOR_PALETTE[9];
} // namespace Bagel
#endif

View File

@@ -0,0 +1,103 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/str.h"
#include "gui/debugger.h"
#include "bagel/boflib/error.h"
#include "bagel/bagel.h"
namespace Bagel {
const char *const g_errList[] = {
"No Error",
"Out of memory",
"Error opening file",
"Error closing file",
"Error reading file",
"Error writing file",
"Error seeking file",
"Error deleting file",
"Could not find file",
"Invalid file type",
"Invalid Path",
"Disk error",
"Unknown Error",
"CRC failure"
};
// Static members
//
int CBofError::_count;
CBofError::CBofError() {
_errCode = ERR_NONE;
}
void CBofError::initialize() {
_count = 0;
}
void CBofError::reportError(ErrorCode errCode, const char *format, ...) {
_errCode = errCode;
if (_errCode == ERR_NONE)
return;
Common::String buf;
// One more error
_count++;
// Don't parse the variable input if there isn't any
if (format != nullptr) {
// Parse the arguments
va_list argptr;
va_start(argptr, format);
buf = Common::String::vformat(format, argptr);
va_end(argptr);
}
// Tell user about error, unless there were too many errors
if (_count < MAX_ERRORS)
bofMessageBox(buf, g_errList[errCode]);
GUI::Debugger *console = g_engine->getDebugger();
if (console->isActive())
console->debugPrintf("%s\n", buf.c_str());
}
void CBofError::fatalError(ErrorCode errCode, const char *format, ...) {
Common::String buf;
// Don't parse the variable input if there isn't any
if (format != nullptr) {
// Parse the arguments
va_list argptr;
va_start(argptr, format);
buf = Common::String::vformat(format, argptr);
va_end(argptr);
}
error("%s - %s", g_errList[errCode], buf.c_str());
}
} // namespace Bagel

View File

@@ -0,0 +1,103 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_ERROR_H
#define BAGEL_BOFLIB_ERROR_H
#include "common/str.h"
namespace Bagel {
/**
* Error reporting codes
*/
enum ErrorCode {
ERR_NONE = 0, /* no error */
ERR_MEMORY = 1, /* not enough memory */
ERR_FOPEN = 2, /* error opening a file */
ERR_FREAD = 4, /* error reading a file */
ERR_FWRITE = 5, /* error writing a file */
ERR_FSEEK = 6, /* error seeking a file */
ERR_FFIND = 8, /* could not find file */
ERR_FTYPE = 9, /* invalid file type */
ERR_UNKNOWN = 12, /* unknown error */
ERR_CRC = 13, /* file or data failed CRC check */
};
#define ERROR_CODE ErrorCode
#define MAX_ERRORS 3
extern const char *const g_errList[];
#define errList g_errList
class CBofError {
protected:
static int _count;
ErrorCode _errCode;
virtual void bofMessageBox(const Common::String &content, const Common::String &title) {
}
public:
CBofError();
virtual ~CBofError() {
}
/**
* Logs specified error to log file.
* @remarks Sets _errCode to specified error condition, and logs the
* error.
* @param errCode Error to report
* @param format A printf style format string
* @param ... Additional parameters to be formatted and inserted into the string
*/
void reportError(ErrorCode errCode, const char *format, ...);
/**
* Logs specified fatal error to log file and exit the game.
* @param errCode Error to report
* @param format A printf style format string
* @param ... Additional parameters to be formatted and inserted into the string
*/
static void fatalError(ErrorCode errCode, const char *format, ...);
bool errorOccurred() const {
return _errCode != ERR_NONE;
}
ErrorCode getErrorCode() const {
return _errCode;
}
void clearError() {
_errCode = ERR_NONE;
}
static void initialize();
static int getErrorCount() {
return _count;
}
};
} // namespace Bagel
#endif

View File

@@ -0,0 +1,55 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/events.h"
#include "bagel/boflib/event_loop.h"
#include "bagel/bagel.h"
#include "bagel/spacebar/baglib/master_win.h"
namespace Bagel {
EventLoop::EventLoop(Mode mode) : _limiter(g_system, 60, false),
_mode(mode) {
}
bool EventLoop::frame() {
Common::Event e;
// Handle pending events
while (g_system->getEventManager()->pollEvent(e)) {
if (g_engine->shouldQuit() || (e.type == Common::EVENT_LBUTTONDOWN) ||
(e.type == Common::EVENT_KEYDOWN && e.kbd.keycode == Common::KEYCODE_ESCAPE))
return true;
}
_limiter.delayBeforeSwap();
// Update the screen
if (_mode == FORCE_REPAINT && g_engine->isSpaceBar())
SpaceBar::CBagMasterWin::forcePaintScreen();
g_engine->getScreen()->update();
_limiter.startFrame();
return false;
}
} // namespace Bagel

View File

@@ -0,0 +1,51 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_EVENT_LOOP_H
#define BAGEL_BOFLIB_EVENT_LOOP_H
#include "graphics/framelimiter.h"
namespace Bagel {
class EventLoop {
public:
enum Mode {
NO_UPDATES = 0, FORCE_REPAINT = 1
};
private:
Graphics::FrameLimiter _limiter;
Mode _mode;
public:
EventLoop(Mode mode = NO_UPDATES);
/**
* Processes pending events and does a frame output.
* @returns True if Escape was pressed to abort loop
*/
bool frame();
};
} // namespace Bagel
#endif

View File

@@ -0,0 +1,90 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "common/savefile.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/macresman.h"
#include "bagel/boflib/file_functions.h"
#include "bagel/bagel.h"
#include "bagel/afxwin.h"
namespace Bagel {
bool fileExists(const char *pszFileName) {
if (g_engine->getPlatform() == Common::kPlatformMacintosh) {
return Common::MacResManager::exists(pszFileName);
} else if (!g_engine->isSpaceBar()) {
return MFC::FileExists(pszFileName);
} else {
return Common::File::exists(pszFileName);
}
}
int32 fileLength(const char *pszFileName) {
Common::SeekableReadStream *stream = nullptr;
if (g_engine->getPlatform() == Common::kPlatformMacintosh) {
stream = Common::MacResManager::openFileOrDataFork(pszFileName);
} else {
stream = SearchMan.createReadStreamForMember(pszFileName);
}
int32 length = -1;
if (stream) {
length = stream->size();
delete stream;
}
return length;
}
char *fileGetFullPath(char *pszDstBuf, const char *pszSrcBuf) {
Common::strcpy_s(pszDstBuf, MAX_DIRPATH, pszSrcBuf);
return pszDstBuf;
}
void fixPathName(CBofString &s) {
// Remove any homedir prefix. In ScummVM, all paths are relative
// to the game folder automatically
char *p = strstr(s.getBuffer(), HOMEDIR_TOKEN);
if (p != nullptr)
s = p + strlen(HOMEDIR_TOKEN) + 1;
// Replace any backslashes with forward slashes
while ((p = strchr(s.getBuffer(), '\\')) != nullptr)
* p = '/';
}
const char *formPath(const char *dir, const char *pszFile) {
assert(dir != nullptr && pszFile != nullptr);
static char szBuf[MAX_DIRPATH];
CBofString cStr(dir);
fixPathName(cStr);
Common::Path path(cStr.getBuffer());
path = path.append(pszFile);
Common::strcpy_s(szBuf, path.toString().c_str());
return &szBuf[0];
}
} // namespace Bagel

View File

@@ -0,0 +1,61 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_FILE_FUNCTIONS_H
#define BAGEL_BOFLIB_FILE_FUNCTIONS_H
#include "common/scummsys.h"
#include "bagel/boflib/string.h"
namespace Bagel {
/**
* Checks to see if specified file exists
* @param pszFileName Name of file to check existence
* @return true if file exists, false if file does not exist
*
**/
// for mac, use this routine to replace the diskid
extern bool fileExists(const char *pszFileName);
/**
* Gets length of file in bytes (via file name)
* @param pszFileName Name of file to get length for
* @return Size of specified file (or -1 if not exist or error)
*/
extern int32 fileLength(const char *pszFileName);
extern char *fileGetFullPath(char *pszDstBuf, const char *pszSrcBuf);
/**
* Takes a directory and filename, merging them to form a
* fully qualified filename. Also takes care of special folder
* aliases at the start of the directory name
*/
extern const char *formPath(const char *dir, const char *pszFile);
extern void fixPathName(CBofString &s);
} // namespace Bagel
#endif

View File

@@ -0,0 +1,167 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/scummsys.h"
#include "bagel/boflib/llist.h"
namespace Bagel {
CLList::CLList() {
_pPrev = nullptr;
_pNext = nullptr;
_pData = nullptr;
}
CLList::CLList(void *pObj) {
_pPrev = nullptr;
_pNext = nullptr;
_pData = pObj;
}
CLList::~CLList() {
this->Delete();
}
void CLList::addToHead(CLList *pNewList) {
// Can't insert a nullptr record into the list
assert(pNewList != nullptr);
CLList *pListHead = getHead();
pNewList->_pNext = pListHead;
pNewList->_pPrev = nullptr;
pListHead->_pPrev = pNewList;
}
void CLList::addToTail(CLList *pNewList) {
// Can't insert a nullptr record into the list
assert(pNewList != nullptr);
CLList *pListTail = getTail();
pNewList->_pPrev = pListTail;
pNewList->_pNext = nullptr;
pListTail->_pNext = pNewList;
}
void CLList::Insert(CLList *pList) {
// Can't insert a nullptr record into the list
assert(pList != nullptr);
pList->_pPrev = this;
pList->_pNext = _pNext;
if (_pNext != nullptr)
_pNext->_pPrev = pList;
_pNext = pList;
}
void CLList::Delete() {
if (_pPrev != nullptr)
_pPrev->_pNext = _pNext;
if (_pNext != nullptr)
_pNext->_pPrev = _pPrev;
_pPrev = _pNext = nullptr;
}
void CLList::MoveToHead() {
CLList *pHead = getHead();
assert(pHead != nullptr);
if (this != pHead) {
Delete();
pHead->addToHead(this);
}
}
void CLList::MoveToTail() {
CLList *pTail = getTail();
assert(pTail != nullptr);
if (this != pTail) {
Delete();
pTail->addToTail(this);
}
}
void CLList::MoveLeft() {
if (_pPrev != nullptr) {
CLList *pPrev = _pPrev->getPrev();
if (pPrev != nullptr) {
Delete();
pPrev->Insert(this);
} else {
MoveToHead();
}
}
}
void CLList::MoveRight() {
CLList *pNext = _pNext;
if (pNext != nullptr) {
this->Delete();
pNext->Insert(this);
}
}
void CLList::FlushList() {
CLList *pList = getHead();
// Something is wrong if the head is invalid
assert(pList != nullptr);
while (pList != nullptr) {
CLList *pTmpList = pList->_pNext;
// Don't delete myself
if (pList != this)
delete pList;
pList = pTmpList;
}
}
CLList *CLList::getHead() {
CLList *pList = this;
while (pList->_pPrev != nullptr)
pList = pList->_pPrev;
return pList;
}
CLList *CLList::getTail() {
CLList *pList = this;
while (pList->_pNext != nullptr)
pList = pList->_pNext;
return pList;
}
} // namespace Bagel

View File

@@ -0,0 +1,136 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_LLIST_H
#define BAGEL_BOFLIB_LLIST_H
namespace Bagel {
/**
* Linked list class
*/
class CLList {
protected:
CLList *_pPrev; // Pointer to next link in chain
CLList *_pNext; // Pointer to previous link in chain
void *_pData; // Pointer to owning CData
public:
/**
* Default constructor
*/
CLList();
/**
* Alternate constructor that initializes with specified data
*/
CLList(void *pObj);
/**
* Destructor
*/
virtual ~CLList();
/**
* Links specified node to current list after current node
* @remarks This will link a new list into the current right after the current node
* @param pNewList Pointer to list to be inserted
*/
void Insert(CLList *pNewList);
/**
* Deletes current node
*/
void Delete();
/**
* Links specified node to head of list
* @remarks This can be used to link 2 lists together by Linking the
* tail of one list to the head of another
* @param pNewList New list to link to head of current list
*/
void addToHead(CLList *pNewList);
/**
* Links specified node to tail of current list
* @remarks This can be used to link 2 lists together by Linking the
* head of one list to the tail of another
* @param pNewList Pointer to new list
*/
void addToTail(CLList *pNewList);
/**
* Moves this item to the head of the linked list
*/
void MoveToHead();
/**
* Moves this item to the tail of the linked list
*/
void MoveToTail();
/**
* Moves this item 1 item to the left
*/
void MoveLeft();
/**
* Moves this item 1 item to the right
*/
void MoveRight();
/**
* Returns head of current list
* @return Pointer to head of list
*/
CLList *getHead();
/**
* Returns tail of current list
* @return Pointer to tail of list
*/
CLList *getTail();
CLList *getPrev() const {
return _pPrev;
}
CLList *getNext() const {
return _pNext;
}
void *getData() const {
return _pData;
}
void PutData(void *pObj) {
_pData = pObj;
}
/**
* Flushes entire list
*/
void FlushList();
};
} // namespace Bagel
#endif

View File

@@ -0,0 +1,69 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "common/savefile.h"
#include "common/debug.h"
#include "bagel/boflib/log.h"
namespace Bagel {
static const char *const g_pszLogTypes[4] = {
"Fatal Error: ",
"Error: ",
"Warning: ",
""
};
void logInfo(const char *msg) {
if (gDebugLevel > 0)
debug("%s", msg);
}
void logWarning(const char *msg) {
if (gDebugLevel > 0)
debug("%s%s", g_pszLogTypes[2], msg);
}
void logError(const char *msg) {
if (gDebugLevel > 0)
debug("%s%s", g_pszLogTypes[1], msg);
}
const char *buildString(const char *pszFormat, ...) {
static char szBuf[256];
va_list argptr;
assert(pszFormat != nullptr);
if (pszFormat != nullptr) {
// Parse the variable argument list
va_start(argptr, pszFormat);
Common::vsprintf_s(szBuf, pszFormat, argptr);
va_end(argptr);
return (const char *)&szBuf[0];
}
return nullptr;
}
} // namespace Bagel

View File

@@ -0,0 +1,40 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_LOG_H
#define BAGEL_BOFLIB_LOG_H
namespace Bagel {
/**
* Builds a string like sprintf()
* @return Pointer to new (temporary) buffer.
*/
const char *buildString(const char *pszFormat, ...);
extern void logInfo(const char *msg);
extern void logWarning(const char *msg);
extern void logError(const char *msg);
} // namespace Bagel
#endif

View File

@@ -0,0 +1,523 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/file.h"
#include "bagel/boflib/misc.h"
#include "bagel/boflib/cache.h"
#include "bagel/bagel.h"
#include "bagel/boflib/string_functions.h"
namespace Bagel {
#define MAX_LINE_LEN 100
static uint32 lStart;
void timerStart() {
lStart = g_system->getMillis();
}
uint32 timerStop() {
return g_system->getMillis() - lStart;
}
uint32 getTimer() {
return g_system->getMillis();
}
void bofSleep(uint32 milli) {
g_system->delayMillis(milli);
}
#define ALLOC_FAIL_RETRIES 2
void *bofMemAlloc(uint32 nSize, const char *pFile, int nLine, bool bClear) {
// For now, until I fix it, pFile MUST be valid.
assert(pFile != nullptr);
assert(nSize != 0);
// Assume failure
void *pNewBlock = nullptr;
// Try a few times to allocate the desired amount of memory.
// Flush objects from Cache is necessary.
for (int nRetries = 0; nRetries < ALLOC_FAIL_RETRIES; nRetries++) {
pNewBlock = (void *)malloc(nSize);
// If allocation was successful, then we're outta here
if (pNewBlock != nullptr) {
if (bClear)
memset((byte *)pNewBlock, 0, nSize);
break;
}
// Otherwise, we need to free up some memory by flushing old
// objects from the Cache.
CCache::optimize(nSize + 2 * sizeof(uint16) + sizeof(uint32));
}
if (pNewBlock == nullptr)
CBofError::fatalError(ERR_MEMORY, "Could not allocate %u bytes, file %s, line %d", nSize, pFile, nLine);
return pNewBlock;
}
void bofMemFree(void *pBuf) {
free(pBuf);
}
Fixed fixedMultiply(Fixed Multiplicand, Fixed Multiplier) {
int64 nTmpNum = (int64)Multiplicand * Multiplier;
Fixed fixResult = (Fixed)(nTmpNum >> 16);
return fixResult;
}
Fixed fixedDivide(Fixed Dividend, Fixed Divisor) {
int64 nBigNum = (int64)Dividend << 16;
Fixed fixResult = (Fixed)(nBigNum / Divisor);
return fixResult;
}
void bofMemSet(void *pSrc, byte chByte, int32 lBytes) {
assert(pSrc != nullptr);
byte *pBuf = (byte *)pSrc;
while (lBytes-- != 0)
*pBuf++ = chByte;
}
void bofMemCopy(void *pDst, const void *pSrc, int32 lLength) {
assert(pDst != nullptr);
assert(pSrc != nullptr);
assert(lLength >= 0);
byte *p1 = (byte *)pDst;
const byte *p2 = (const byte *)pSrc;
while (lLength-- != 0) {
*p1++ = *p2++;
}
}
bool readLine(Common::SeekableReadStream *fp, char *pszBuf) {
if (fp->eos())
return false;
Common::String line = fp->readLine();
Common::strcpy_s(pszBuf, MAX_LINE_LEN, line.c_str());
strreplaceChar(pszBuf, '\n', '\0');
return true;
}
void encrypt(void *pBuf, int32 size, const char *pszPassword) {
assert(pBuf != nullptr);
const char *pStart = pszPassword;
if (!pszPassword || strlen(pszPassword) == 0) {
pStart = "\0\0";
}
byte *p = (byte *)pBuf;
const char *pPW = pStart;
while (--size >= 0) {
*p ^= (byte)(0xD2 + size + *pPW);
p++;
if (*pPW++ == '\0') {
pPW = pStart;
}
}
}
void encryptPartial(void *pBuf, int32 fullSize, int32 lBytes, const char *pszPassword) {
assert(pBuf != nullptr);
const char *pStart = pszPassword;
if (!pszPassword || strlen(pszPassword) == 0) {
pStart = "\0\0";
}
byte *p = (byte *)pBuf;
const char *pPW = pStart;
while (--lBytes >= 0) {
fullSize--;
*p ^= (byte)(0xD2 + fullSize + *pPW);
p++;
if (*pPW++ == '\0') {
pPW = pStart;
}
}
}
int mapWindowsPointSize(int pointSize) {
return pointSize;
}
void ErrorLog(const char *logFile, const char *format, ...) {
// No implementation
}
int StrFreqMatch(const char *mask, const char *test) {
static int nCount[256];
int i, divergence;
/* can't access null pointers */
assert(mask != nullptr);
assert(test != nullptr);
/* assume no match by making the divergence really high */
divergence = 100;
/*
* the first letter has to match before we even think about continuing
*/
if (*mask == *test) {
/* reset the frequency count */
memset(nCount, 0, sizeof(int) * 256);
/* count the frequency of the chars in 'mask' */
while (*mask != '\0')
nCount[(int)*mask++] += 1;
/* subtract off the frequency of the chars in 'test' */
while (*test != '\0')
nCount[(int)*test++] -= 1;
/*
* total all of the frequencies
*/
divergence = 0;
for (i = 0; i <= 255; i++)
divergence += abs(nCount[i]);
}
/* returning a 0 or 1 means that the strings are almost identical */
return (divergence);
}
bool StrCompare(const char *pszStr1, const char *pszStr2, unsigned int nSize) {
char *s1, *p, string1[256]; /* replace this stack hog with malloc */
char *s2, *sp, string2[256]; /* replace this stack hog with malloc */
int i, n, inc;
bool bMatch;
/* can't access null pointers */
assert(pszStr1 != nullptr);
assert(pszStr2 != nullptr);
/* make sure that we are not going to blow the stack */
assert(strlen(pszStr1) < 256);
assert(strlen(pszStr2) < 256);
p = s1 = string1;
s2 = string2;
/*
* Reset these buffers to garuntee the strings will terminate
*/
memset(s1, 0, 256);
memset(s2, 0, 256);
/* make local copies of the strings */
Common::sprintf_s(s1, 256, " %s", pszStr1);
Common::sprintf_s(s2, 256, " %s", pszStr2);
/*
* make "THE", "AN", and "A" be special tokens - make them uppercase while
* all other words are lowercase.
*/
strLower(s1);
StrUprStr(s1, " the ");
StrUprStr(s1, " an ");
StrUprStr(s1, " a ");
if ((sp = strstr(s2, " THE ")) != nullptr) {
memmove(sp, sp + 5, strlen(sp + 5) + 1);
}
/*
* strip out all unwanted characters
*/
/* strip out all spaces
*/
StrStripChar(s1, ' ');
StrStripChar(s2, ' ');
/* strip out any apostrophes
*/
StrStripChar(s1, 39);
StrStripChar(s2, 39);
/* strip out any commas
*/
StrStripChar(s1, ',');
StrStripChar(s2, ',');
/* strip out any dashes
*/
StrStripChar(s1, '-');
StrStripChar(s2, '-');
/*
* add a buffer zone to the end of both strings
* (this might now be obsolete)
*/
Common::strcat_s(s1, 256, " ");
Common::strcat_s(s2, 256, " ");
/*
* compare the 2 strings, if we get a "THE", "A", or "AN" (case sensative)
* then do a special compare
*/
/* assume they match */
bMatch = true;
i = 0;
n = strlen(s1);
while (i++ < n) {
/*
* handle special tokens
*/
if ((*s1 == 'T') || (*s1 == 'A')) {
inc = 3;
if (*s1 == 'A') {
inc = 1;
if (*(s1 + 1) == 'N') {
inc = 2;
}
}
p = s1;
if (toupper(*s1) != toupper(*s2)) {
s1 += inc;
i += inc;
} else {
p = s1 + inc;
i += inc;
}
}
if ((toupper(*s1) != toupper(*s2)) && (toupper(*p) != toupper(*s2))) {
bMatch = false;
break;
}
s1++;
s2++;
p++;
}
return (bMatch);
}
/*****************************************************************************
*
* StrCharCount - Counts number of occurences of a specified char in String
*
* DESCRIPTION: Counts the number of times the specified character occurs
* in the given string.
*
* SAMPLE USAGE:
* n = StrCharCount(str, c);
* const char *str; pointer to string to parse
* char c; character to count in str
*
* RETURNS: int = number of times character c occurs in string str
*
*****************************************************************************/
int StrCharCount(const char *str, char c) {
int n;
assert(str != nullptr);
assert(strlen(str) <= 255);
n = 0;
while (*str != '\0') {
if (*str++ == c)
n++;
}
return (n);
}
/**
* name StriStr - same as strstr() except ignores case
*
* synopsis s = StriStr(s1, s2)
* const char *s1 string to parse
* const char *s2 substring to find in s1
*
* purpose To search for a string inside another string while ignoring case
*
*
* returns pointer to substring s2 in s1 or nullptr if not found
*
**/
char *StriStr(char *s1, const char *s2) {
char *p, str1[80];
char str2[80];
/* can't access null pointers */
assert(s1 != nullptr);
assert(s2 != nullptr);
/* make sure we don't blow the stack */
assert(strlen(s1) < 80);
assert(strlen(s2) < 80);
/* copy to local buffers */
Common::strcpy_s(str1, s1);
Common::strcpy_s(str2, s2);
/* convert to upper case */
strUpper(str1);
strUpper(str2);
/* find str2 in str1 */
p = strstr(str1, str2);
/* re-point to original string s1 */
if (p != nullptr) {
p = s1 + (p - str1);
}
return (p);
}
void StrUprStr(char *s1, const char *s2) {
char *p;
int i, n;
/* can't access null pointers */
assert(s1 != nullptr);
assert(s2 != nullptr);
p = s1;
while ((p = StriStr(p, s2)) != nullptr) {
n = strlen(s2);
for (i = 0; i < n; i++) {
*p = (char)toupper(*p);
p++;
}
}
}
/**
* name StrCpyStripChar - Same as Common::strcpy_s() except specified character
* will be stripped from the destination string.
*
* synopsis StrCpyStripChar(dest, source, c)
* char *dest destinaton string
* const char *source source string
* char c character to strip from dest
*
* purpose To strip out a specified character while copying 1 string to another
*
*
* returns Nothing
*
**/
void StrCpyStripChar(char *dest, const char *source, char c) {
/* can't access null pointers */
assert(dest != nullptr);
assert(source != nullptr);
/* source and destination cannot be the same */
assert(dest != source);
do {
if ((*dest = *source) != c)
dest++;
} while (*source++ != '\0');
}
char *StrStripChar(char *str, char c) {
char *p = str;
/* can't acces a null pointer */
assert(str != nullptr);
/* if c was '\0' then this function would do nothing */
assert(c != '\0');
while (*p != '\0') {
if (*p == c) {
/* move the string left 1 byte (including the terminator) */
memmove(p, p + 1, strlen(p + 1) + 1);
}
p++;
}
return (str);
}
char *StrReplaceChar(char *str, char cOld, char cNew) {
char *p = str;
/* can't acces a null pointer */
assert(str != nullptr);
/* if cOld was '\0' then this function would do nothing */
assert(cOld != '\0');
while (*p != '\0') {
if (*p == cOld) {
*p = cNew;
}
p++;
}
return (str);
}
/**
* name ProbableTrue
* synopsis - return a true / false based on the probability given
* int nProbability the probability of returning a true
*
* purpose to return a true <nProbability> of the tine
*
*
* returns bool
*
**/
bool ProbableTrue(int nProbability) {
int nRand = brand() % 100;
return (nRand < nProbability);
}
} // namespace Bagel

124
engines/bagel/boflib/misc.h Normal file
View File

@@ -0,0 +1,124 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_MISC_H
#define BAGEL_BOFLIB_MISC_H
#include "bagel/boflib/stdinc.h"
namespace Bagel {
extern int mapWindowsPointSize(int pointSize);
/**
* Starts a Millisecond timer
*/
extern void timerStart();
/**
* Stops the timer started by timerStart, returns time elapsed.
* @return Number of MilliSeconds elapsed since call to timerStart
*/
extern uint32 timerStop();
/**
* Returns the current elapsed time in milliseconds
*/
extern uint32 getTimer();
/**
* Pauses the computer for specified number of MilliSeconds
* @param milli Number of milliseconds
*/
extern void bofSleep(uint32 milli);
extern Fixed fixedDivide(Fixed Dividend, Fixed Divisor);
extern Fixed fixedMultiply(Fixed Multiplicand, Fixed Multiplier);
#define intToFixed(i) (Fixed)(((long)(i)) << 16)
#define fixedToInt(f) (int)(((long)(f)) >> 16)
//////////////////////////////////////////////////////////////////////////////
//
// Memory allocation routines (Should be put into their own MEMORY module)
//
//////////////////////////////////////////////////////////////////////////////
/**
* Allocates a memory block of specified size
* @param nSize Number of bytes to allocate
* @param pFile Source file name
* @param nLine Source file line number
* @param bClear true if buffer should be cleared
* @return Pointer to new buffer
*/
extern void *bofMemAlloc(uint32 nSize, const char *pFile, int nLine, bool bClear);
/**
* Frees specified memory block
* @param pBuf Buffer to de-allocate
**/
extern void bofMemFree(void *pBuf);
#define bofAlloc(n) bofMemAlloc((n), __FILE__, __LINE__, false)
#define bofCleanAlloc(n) bofMemAlloc((n), __FILE__, __LINE__, true)
#define bofFree(p) bofMemFree((p))
inline uint32 getFreePhysMem() {
return 999999;
}
/**
* Encrypts specified buffer
* @param pBuf Buffer to encrypt
* @param lSize Number of bytes in buffer
* @param pszPassword Optional password to encrypt with
*/
void encrypt(void *pBuf, int32 lSize, const char *pszPassword = nullptr);
#define decrypt encrypt
#define Decrypt encrypt
extern void encryptPartial(void *, int32, int32, const char *pPassword = nullptr);
#define decryptPartial encryptPartial
/**
* Return a true / false based on the probability given
* @param nProbability The probability of returning a true
* @returns True/false result
**/
extern bool ProbableTrue(int nProbability);
extern void ErrorLog(const char *logFile, const char *format, ...);
extern int StrFreqMatch(const char *, const char *);
extern bool StrCompare(const char *, const char *, unsigned int);
extern int StrCharCount(const char *, char);
extern char *StriStr(char *, const char *);
extern void StrUprStr(char *, const char *);
extern void StrCpyStripChar(char *, const char *, char);
extern char *StrStripChar(char *, char);
extern char *StrReplaceChar(char *, char, char);
} // namespace Bagel
#endif

View File

@@ -0,0 +1,40 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_OBJECT_H
#define BAGEL_BOFLIB_OBJECT_H
namespace Bagel {
class CBofObject {
public:
virtual ~CBofObject() {}
static bool isValidObject(const CBofObject *pObject) {
return true;
}
virtual void DeleteObject() {}
};
} // namespace Bagel
#endif

View File

@@ -0,0 +1,161 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/file.h"
#include "graphics/palette.h"
#include "image/bmp.h"
#include "bagel/boflib/palette.h"
#include "bagel/spacebar/boflib/app.h"
#include "bagel/spacebar/boflib/file.h"
#include "bagel/boflib/file_functions.h"
namespace Bagel {
namespace SpaceBar {
CBofPalette *CBofPalette::_pSharedPalette;
char CBofPalette::_szSharedPalFile[MAX_FNAME];
PaletteData::PaletteData(int16 numColors) : _numColors(numColors) {
Common::fill(&_data[0], &_data[Graphics::PALETTE_SIZE], 0);
}
void CBofPalette::initialize() {
_pSharedPalette = nullptr;
_szSharedPalFile[0] = '\0';
}
CBofPalette::CBofPalette() {
Common::fill(&_palette._data[0], &_palette._data[Graphics::PALETTE_SIZE], 0);
}
CBofPalette::CBofPalette(const char *pszFileName) {
Common::fill(&_palette._data[0], &_palette._data[Graphics::PALETTE_SIZE], 0);
assert(pszFileName != nullptr);
loadPalette(pszFileName);
}
CBofPalette::CBofPalette(const PaletteData &paletteData) {
_palette = paletteData;
}
CBofPalette::~CBofPalette() {
assert(isValidObject(this));
// If we trash the games palette, then reset it back to nullptr.
CBofApp *pApp = CBofApp::getApp();
if (pApp != nullptr) {
if (this == pApp->getPalette()) {
pApp->setPalette(nullptr);
}
}
ReleasePalette();
}
void CBofPalette::setPalette(const PaletteData &PaletteData) {
assert(isValidObject(this));
ReleasePalette();
_palette = PaletteData;
}
ErrorCode CBofPalette::loadPalette(const char *pszFileName, uint16 nFlags) {
assert(isValidObject(this));
// Validate input
assert(pszFileName != nullptr);
ReleasePalette();
// Load in new bitmap file to get the palette
Common::File f;
Image::BitmapDecoder decoder;
if (f.open(pszFileName) && decoder.loadStream(f)) {
// Copy the palette
const Graphics::Palette &pal = decoder.getPalette();
_palette._numColors = pal.size();
pal.grab(_palette._data, 0, pal.size());
_errCode = ERR_NONE;
} else {
_errCode = ERR_FREAD;
}
return _errCode;
}
void CBofPalette::ReleasePalette() {
Common::fill(_palette._data, _palette._data + Graphics::PALETTE_SIZE, 0);
}
CBofPalette *CBofPalette::copyPalette() {
assert(isValidObject(this));
return nullptr;
}
byte CBofPalette::getNearestIndex(COLORREF stRGB) {
Graphics::PaletteLookup lookup(_palette._data, Graphics::PALETTE_COUNT);
return lookup.findBestColor(GetRed(stRGB), GetGreen(stRGB), GetBlue(stRGB));
}
COLORREF CBofPalette::getColor(byte nIndex) {
const byte *rgb = &_palette._data[nIndex * 3];
COLORREF cColor = RGB(rgb[0], rgb[1], rgb[2]);
return cColor;
}
ErrorCode CBofPalette::createDefault(uint16 nFlags) {
assert(isValidObject(this));
byte *pal = _palette._data;
for (int i = 0; i < 256; ++i, pal += 3)
pal[0] = pal[1] = pal[2] = (byte)i;
return ERR_NONE;
}
ErrorCode CBofPalette::setSharedPalette(const char *pszFileName) {
delete _pSharedPalette;
_pSharedPalette = nullptr;
// Save name of file used to get the shared palette
if (pszFileName != nullptr) {
Common::strcpy_s(_szSharedPalFile, pszFileName);
}
return ERR_NONE;
}
CBofPalette *CBofPalette::getSharedPalette() {
// Do we need to load the shared palette?
if (_pSharedPalette == nullptr && fileExists(_szSharedPalFile))
_pSharedPalette = new CBofPalette(_szSharedPalFile);
return _pSharedPalette;
}
} // namespace SpaceBar
} // namespace Bagel

View File

@@ -0,0 +1,153 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_GFX_PALETTE_H
#define BAGEL_BOFLIB_GFX_PALETTE_H
#include "graphics/palette.h"
#include "bagel/afxwin.h"
#include "bagel/boflib/error.h"
#include "bagel/boflib/object.h"
#include "bagel/boflib/stdinc.h"
namespace Bagel {
namespace SpaceBar {
struct PaletteData {
byte _data[Graphics::PALETTE_SIZE];
int16 _numColors;
PaletteData(int16 numColors = Graphics::PALETTE_COUNT);
};
struct PALETTEENTRY {
byte peRed;
byte peGreen;
byte peBlue;
byte peFlags;
};
struct LOGPALETTE {
int16 palNumEntries;
int16 palVersion;
PALETTEENTRY palPalEntry[1];
};
struct BOFRGBQUAD {
byte rgbBlue;
byte rgbGreen;
byte rgbRed;
byte rgbReserved;
};
#define GetRed(rgb) ((byte)((rgb) & 0x000000FF))
#define GetGreen(rgb) ((byte)(((rgb) >> 8) & 0x000000FF))
#define GetBlue(rgb) ((byte)(((rgb) >> 16) & 0x000000FF))
class CBofPalette : public CBofError, public CBofObject {
protected:
PaletteData _palette;
static CBofPalette *_pSharedPalette;
static char _szSharedPalFile[MAX_FNAME];
/**
* Deletes internal palette info
*/
void ReleasePalette();
public:
/**
* Default constructor
*/
CBofPalette();
/**
* Constructor that loads a palette from a file
* @param pszFileName filename
*/
CBofPalette(const char *pszFileName);
/**
* Constructor that takes in an existing palette
*/
CBofPalette(const PaletteData &paletteData);
/**
* Loads palette from specified bitmap-file
* @param pszFileName Name of file to load palette from
* @param nFlags Flags for animation, etc...
* @return Error return Code
*/
ErrorCode loadPalette(const char *pszFileName, uint16 nFlags = PAL_DEFAULT);
ErrorCode createDefault(uint16 nFlags = PAL_DEFAULT);
byte getNearestIndex(COLORREF cColor);
COLORREF getColor(byte nIndex);
/**
* Assigns specified palette to this CBofPalette
* @param PaletteData Handle to windows palette
*/
void setPalette(const PaletteData &PaletteData);
const PaletteData &getPalette() const {
return _palette;
}
const byte *getData() const {
return _palette._data;
}
void setData(const byte* colors) {
memcpy(_palette._data, colors, Graphics::PALETTE_SIZE);
}
virtual ~CBofPalette();
/**
* Create a new palette based on current palette
*/
CBofPalette *copyPalette();
/**
* initialize static class fields
*/
static void initialize();
/**
* Called only in response to "SHAREDPAL=filename" in a script file
* @param pszFileName Palette filename
*/
static ErrorCode setSharedPalette(const char *pszFileName);
/**
* Returns the current shared palette
* @return Pointer to shared palette
*/
static CBofPalette *getSharedPalette();
};
} // namespace SpaceBar
} // namespace Bagel
#endif

View File

@@ -0,0 +1,254 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_POINT_H
#define BAGEL_BOFLIB_POINT_H
#include "bagel/afxwin.h"
#include "bagel/boflib/stdinc.h"
#include "bagel/boflib/object.h"
namespace Bagel {
class CBofPoint : public StPoint, public CBofObject {
public:
// Constructors
CBofPoint();
CBofPoint(int initX, int initY);
CBofPoint(StPoint stPoint);
CBofPoint(const CBofPoint &cPoint);
CBofPoint(const StSize &stSize);
CBofPoint(const Common::Point &pt);
CBofPoint(const POINT &stPoint) {
setWinPoint(&stPoint);
}
virtual ~CBofPoint() {
}
void setWinPoint(const POINT *pPoint);
POINT GetWinPoint() const;
void operator=(const POINT &stPoint) {
setWinPoint(&stPoint);
}
operator const POINT() {
return GetWinPoint();
}
// Operations
void offset(int xOffset, int yOffset);
void offset(StPoint point);
void offset(StSize size);
void operator=(const StPoint &point);
void operator=(const CBofPoint &point);
bool operator==(StPoint point) const;
bool operator!=(StPoint point) const;
void operator+=(StSize size);
void operator-=(StSize size);
void operator+=(StPoint point);
void operator-=(StPoint point);
// Operators returning CBofPoint values
CBofPoint operator+(StSize size) const;
CBofPoint operator+(StPoint point) const;
CBofPoint operator-(StSize size) const;
CBofPoint operator-(StPoint point) const;
CBofPoint operator-() const;
};
// CBofPoint
inline CBofPoint::CBofPoint() {
x = 0;
y = 0;
}
inline CBofPoint::CBofPoint(const int initX, const int initY) {
x = initX;
y = initY;
}
inline CBofPoint::CBofPoint(const StPoint stPoint) {
x = stPoint.x;
y = stPoint.y;
}
inline CBofPoint::CBofPoint(const StSize &stSize) {
x = stSize.cx;
y = stSize.cy;
}
inline CBofPoint::CBofPoint(const CBofPoint &cPoint) {
x = cPoint.x;
y = cPoint.y;
}
inline CBofPoint::CBofPoint(const Common::Point &pt) {
x = pt.x;
y = pt.y;
}
inline void CBofPoint::setWinPoint(const POINT *pPoint) {
assert(pPoint != nullptr);
assert(isValidObject(this));
x = pPoint->x;
y = pPoint->y;
}
inline POINT CBofPoint::GetWinPoint() const {
assert(isValidObject(this));
POINT stPoint;
stPoint.x = x;
stPoint.y = y;
return stPoint;
}
inline void CBofPoint::offset(int xOffset, int yOffset) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
x += xOffset;
y += yOffset;
}
inline void CBofPoint::offset(StPoint point) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
x += point.x;
y += point.y;
}
inline void CBofPoint::offset(StSize size) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
x += size.cx;
y += size.cy;
}
inline void CBofPoint::operator=(const StPoint &point) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
x = point.x;
y = point.y;
}
inline void CBofPoint::operator=(const CBofPoint &point) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
x = point.x;
y = point.y;
}
inline bool CBofPoint::operator==(StPoint point) const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return (x == point.x && y == point.y);
}
inline bool CBofPoint::operator!=(StPoint point) const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return (x != point.x || y != point.y);
}
inline void CBofPoint::operator+=(StSize size) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
x += size.cx;
y += size.cy;
}
inline void CBofPoint::operator+=(StPoint point) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
x += point.x;
y += point.y;
}
inline void CBofPoint::operator-=(StPoint point) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
x -= point.x;
y -= point.y;
}
inline void CBofPoint::operator-=(StSize size) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
x -= size.cx;
y -= size.cy;
}
inline CBofPoint CBofPoint::operator+(StSize size) const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofPoint(x + size.cx, y + size.cy);
}
inline CBofPoint CBofPoint::operator+(StPoint point) const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofPoint(x + point.x, y + point.y);
}
inline CBofPoint CBofPoint::operator-(StSize size) const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofPoint(x - size.cx, y - size.cy);
}
inline CBofPoint CBofPoint::operator-(StPoint point) const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofPoint(x - point.x, y - point.y);
}
inline CBofPoint CBofPoint::operator-() const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofPoint(-x, -y);
}
} // namespace Bagel
#endif

View File

@@ -0,0 +1,113 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "bagel/boflib/queue.h"
#include "bagel/boflib/stdinc.h"
namespace Bagel {
CQueue::CQueue() {
}
CQueue::~CQueue() {
// Can't destruct if we don't exist
assert(isValidObject(this));
while (removeItem() != nullptr) {
}
// remove() must set _pQueueList to nullptr when it removes the last item
assert(_pQueueList == nullptr);
}
void CQueue::addItem(void *pObject) {
// Make sure this object exists
assert(isValidObject(this));
CLList *pNewItem = new CLList(pObject);
if (_pQueueList != nullptr) {
_pQueueList->addToTail(pNewItem);
} else {
_pQueueList = pNewItem;
}
assert(pNewItem->getHead() == _pQueueList);
}
void *CQueue::removeItem() {
// Make sure this object exists
assert(isValidObject(this));
// Assume empty list
void *pObject = nullptr;
CLList *pList = _pQueueList;
if (pList != nullptr) {
pObject = pList->getData();
_pQueueList = pList->getNext();
delete pList;
}
return pObject;
}
void CQueue::deleteItem(void *pItem) {
// Make sure this object exists
assert(isValidObject(this));
assert(pItem != nullptr);
CLList *pList = _pQueueList;
while (pList != nullptr) {
CLList *pNext = pList->getNext();
if (pItem == pList->getData()) {
// If this is the 1st item in the Queue, then move head
if (pList == _pQueueList)
_pQueueList = _pQueueList->getNext();
delete pList;
break;
}
pList = pNext;
}
}
void *CQueue::getQItem() {
assert(isValidObject(this));
void *pItem = nullptr;
if (_pQueueList != nullptr) {
pItem = _pQueueList->getData();
}
return pItem;
}
void CQueue::flush() {
assert(isValidObject(this));
while (removeItem() != nullptr) {
}
}
} // namespace Bagel

View File

@@ -0,0 +1,78 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_QUEUE_H
#define BAGEL_BOFLIB_QUEUE_H
#include "bagel/boflib/object.h"
#include "bagel/boflib/llist.h"
namespace Bagel {
class CQueue : public CBofObject {
protected:
CLList *_pQueueList = nullptr;
public:
/**
* Default constructor
*/
CQueue();
/**
* Destructor
*/
virtual ~CQueue();
/**
* Pushes object onto stack
* @param pObject Pointer to object to be pushed
*/
void addItem(void *pObject);
/**
* Removes 1 object off stack
* @return Pointer to top object on stack
*/
void *removeItem();
/**
* Retrieves the 1st item (FIFO order) without removing it.
* @return 1st item in Queue (or nullptr is Queue is empty)
*/
void *getQItem();
/**
* Deletes specified item from the QUEUE (Illegally)
* @param pObject Object to remove
*/
void deleteItem(void *pObject);
/**
* Removes all items from the queue
*/
void flush();
};
} // namespace Bagel
#endif

455
engines/bagel/boflib/rect.h Normal file
View File

@@ -0,0 +1,455 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_RECT_H
#define BAGEL_BOFLIB_RECT_H
#include "common/rect.h"
#include "bagel/afxwin.h"
#include "bagel/boflib/stdinc.h"
#include "bagel/boflib/object.h"
#include "bagel/boflib/point.h"
#include "bagel/boflib/size.h"
namespace Bagel {
class CBofRect : public CBofObject {
public:
// Constructors
CBofRect();
CBofRect(int l, int t, int r, int b);
CBofRect(const CBofRect &srcRect);
CBofRect(const CBofPoint &point, const CBofSize &size);
CBofRect(const CBofPoint &pttopLeft, const CBofPoint &ptBottomRight);
virtual ~CBofRect() {
}
// Attributes
int width() const;
int height() const;
CBofSize size() const;
CBofPoint topLeft() const;
CBofPoint bottomRight() const;
CBofPoint topRight() const;
CBofPoint bottomLeft() const;
bool isRectEmpty() const;
bool isRectNull() const;
bool ptInRect(const CBofPoint &point) const;
// Operations
inline void setRect(int x1, int y1, int x2, int y2);
void setRectEmpty();
void copyRect(const CBofRect &cRect);
bool equalRect(const CBofRect &cRect);
CBofRect(const RECT &cRect) {
setWinRect(&cRect);
}
CBofRect(const RECT *pRect) {
setWinRect(pRect);
}
void setWinRect(const RECT *pRect);
RECT getWinRect();
void operator=(const RECT &srcRect) {
setWinRect(&srcRect);
}
void operator=(const Common::Rect &srcRect) {
const RECT r = { srcRect.left, srcRect.top, srcRect.right, srcRect.bottom };
setWinRect(&r);
}
operator const RECT() {
return getWinRect();
}
operator const Common::Rect() {
return Common::Rect(left, top, right, bottom);
}
void offsetRect(int x, int y);
void offsetRect(const CBofSize &size);
void offsetRect(const CBofPoint &point);
// Operations that fill '*this' with result
bool intersectRect(const CBofRect *pRect1, const CBofRect *pRect2);
bool intersectRect(const CBofRect &cRect1, const CBofRect &cRect2);
bool unionRect(const CBofRect *pRect1, const CBofRect *pRect2);
// Additional Operations
void operator=(const CBofRect &srcRect);
bool operator==(const CBofRect &rect);
bool operator!=(const CBofRect &rect);
void operator+=(const CBofPoint &point);
void operator-=(const CBofPoint &point);
void operator&=(const CBofRect &rect);
void operator|=(const CBofRect &rect);
// Operators returning CBofRect values
CBofRect operator+(const CBofPoint &point);
CBofRect operator-(const CBofPoint &point);
CBofRect operator&(const CBofRect &rect2);
CBofRect operator|(const CBofRect &rect2);
int left;
int top;
int right;
int bottom;
};
inline CBofRect::CBofRect() {
top = left = 0;
right = bottom = -1;
}
inline CBofRect::CBofRect(int l, int t, int r, int b) {
left = l;
top = t;
right = r;
bottom = b;
}
inline CBofRect::CBofRect(const CBofRect &srcRect) {
left = srcRect.left;
top = srcRect.top;
right = srcRect.right;
bottom = srcRect.bottom;
}
inline CBofRect::CBofRect(const CBofPoint &point, const CBofSize &size) {
right = (left = point.x) + size.cx - 1;
bottom = (top = point.y) + size.cy - 1;
}
inline CBofRect::CBofRect(const CBofPoint &pttopLeft, const CBofPoint &ptBottomRight) {
setRect(pttopLeft.x, pttopLeft.y, ptBottomRight.x, ptBottomRight.y);
}
inline int CBofRect::width() const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return right - left + 1;
}
inline int CBofRect::height() const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return bottom - top + 1;
}
inline CBofSize CBofRect::size() const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofSize(width(), height());
}
inline CBofPoint CBofRect::topLeft() const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofPoint(left, top);
}
inline CBofPoint CBofRect::bottomRight() const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofPoint(right, bottom);
}
inline CBofPoint CBofRect::topRight() const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofPoint(right, top);
}
inline CBofPoint CBofRect::bottomLeft() const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofPoint(left, bottom);
}
inline bool CBofRect::isRectEmpty() const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return (width() <= 0 || height() <= 0);
}
inline bool CBofRect::isRectNull() const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return (left == 0 && right == 0 && top == 0 && bottom == 0);
}
inline bool CBofRect::ptInRect(const CBofPoint &point) const {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return (point.x >= left && point.x <= right && point.y >= top && point.y <= bottom);
}
inline void CBofRect::setRect(int x1, int y1, int x2, int y2) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
left = x1;
top = y1;
right = x2;
bottom = y2;
}
inline void CBofRect::setRectEmpty() {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
left = top = 0;
right = bottom = -1;
// Verify that the rectangle is now empty
assert(isRectEmpty());
}
inline void CBofRect::copyRect(const CBofRect &cSrcRect) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
assert(isValidObject(&cSrcRect));
left = cSrcRect.left;
right = cSrcRect.right;
top = cSrcRect.top;
bottom = cSrcRect.bottom;
}
inline bool CBofRect::equalRect(const CBofRect &cRect) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
assert(isValidObject(&cRect));
return (left == cRect.left && right == cRect.right && top == cRect.top && bottom == cRect.bottom);
}
inline RECT CBofRect::getWinRect() {
assert(isValidObject(this));
RECT stRect;
stRect.left = left;
stRect.top = top;
stRect.right = right + 1;
stRect.bottom = bottom + 1;
return stRect;
}
inline void CBofRect::setWinRect(const RECT *pRect) {
assert(isValidObject(this));
assert(pRect != nullptr);
left = pRect->left;
top = pRect->top;
right = pRect->right - 1;
bottom = pRect->bottom - 1;
}
inline void CBofRect::offsetRect(int x, int y) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
left += x;
right += x;
top += y;
bottom += y;
}
inline void CBofRect::offsetRect(const CBofPoint &point) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
left += point.x;
right += point.x;
top += point.y;
bottom += point.y;
}
inline void CBofRect::offsetRect(const CBofSize &size) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
left += size.cx;
right += size.cx;
top += size.cy;
bottom += size.cy;
}
inline bool CBofRect::intersectRect(const CBofRect *pRect1, const CBofRect *pRect2) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
// Can't access null pointers
assert(pRect1 != nullptr);
assert(pRect2 != nullptr);
left = MAX(pRect1->left, pRect2->left);
top = MAX(pRect1->top, pRect2->top);
right = MIN(pRect1->right, pRect2->right);
bottom = MIN(pRect1->bottom, pRect2->bottom);
return ((width() > 0) && (height() > 0));
}
inline bool CBofRect::intersectRect(const CBofRect &cRect1, const CBofRect &cRect2) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return intersectRect(&cRect1, &cRect2);
}
inline bool CBofRect::unionRect(const CBofRect *pRect1, const CBofRect *pRect2) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
// Can't access null pointers
assert(pRect1 != nullptr);
assert(pRect2 != nullptr);
left = MIN(pRect1->left, pRect2->left);
top = MIN(pRect1->top, pRect2->top);
right = MAX(pRect1->right, pRect2->right);
bottom = MAX(pRect1->bottom, pRect2->bottom);
return isRectEmpty();
}
inline void CBofRect::operator=(const CBofRect &srcRect) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
left = srcRect.left;
right = srcRect.right;
top = srcRect.top;
bottom = srcRect.bottom;
}
inline bool CBofRect::operator==(const CBofRect &rect) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return (left == rect.left && right == rect.right &&
top == rect.top && bottom == rect.bottom);
}
inline bool CBofRect::operator!=(const CBofRect &rect) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return (left != rect.left || right != rect.right ||
top != rect.top || bottom != rect.bottom);
}
inline void CBofRect::operator+=(const CBofPoint &point) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
offsetRect(point);
}
inline void CBofRect::operator-=(const CBofPoint &point) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
offsetRect(-point.x, -point.y);
}
inline void CBofRect::operator&=(const CBofRect &rect) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
intersectRect(this, &rect);
}
inline void CBofRect::operator|=(const CBofRect &rect) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
unionRect(this, &rect);
}
inline CBofRect CBofRect::operator+(const CBofPoint &pt) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
CBofRect rect(*this);
rect.offsetRect(pt.x, pt.y);
return rect;
}
inline CBofRect CBofRect::operator-(const CBofPoint &pt) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
CBofRect rect(*this);
rect.offsetRect(-pt.x, -pt.y);
return rect;
}
inline CBofRect CBofRect::operator&(const CBofRect &rect2) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
CBofRect rect;
rect.intersectRect(this, &rect2);
return rect;
}
inline CBofRect CBofRect::operator|(const CBofRect &rect2) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
CBofRect rect;
rect.unionRect(this, &rect2);
return rect;
}
} // namespace Bagel
#endif

139
engines/bagel/boflib/size.h Normal file
View File

@@ -0,0 +1,139 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_SIZE_H
#define BAGEL_BOFLIB_SIZE_H
#include "bagel/afxwin.h"
#include "bagel/boflib/stdinc.h"
#include "bagel/boflib/object.h"
namespace Bagel {
class CBofSize : public SIZE, public CBofObject {
public:
// Constructors
CBofSize();
virtual ~CBofSize() {
}
CBofSize(int initCX, int initCY);
CBofSize(const SIZE &stSize);
CBofSize(const CBofSize &cSize);
CBofSize(StPoint stPoint);
// Operations
void operator=(const CBofSize &cSize);
bool operator==(SIZE size);
bool operator!=(SIZE size);
void operator+=(SIZE size);
void operator-=(SIZE size);
// Operators returning CBofSize values
CBofSize operator+(SIZE size);
CBofSize operator-(SIZE size);
CBofSize operator-();
};
// CBofSize
inline CBofSize::CBofSize() {
cx = cy = 0;
}
inline CBofSize::CBofSize(int initCX, int initCY) {
cx = initCX;
cy = initCY;
}
inline CBofSize::CBofSize(const SIZE &stSize) {
cx = stSize.cx;
cy = stSize.cy;
}
inline CBofSize::CBofSize(const CBofSize &cSize) {
cx = cSize.cx;
cy = cSize.cy;
}
inline CBofSize::CBofSize(StPoint stPoint) {
cx = stPoint.x;
cy = stPoint.y;
}
inline void CBofSize::operator=(const CBofSize &cSize) {
cx = cSize.cx;
cy = cSize.cy;
}
inline bool CBofSize::operator==(SIZE size) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return (cx == size.cx && cy == size.cy);
}
inline bool CBofSize::operator!=(SIZE size) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return (cx != size.cx || cy != size.cy);
}
inline void CBofSize::operator+=(SIZE size) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
cx += size.cx;
cy += size.cy;
}
inline void CBofSize::operator-=(SIZE size) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
cx -= size.cx;
cy -= size.cy;
}
inline CBofSize CBofSize::operator+(SIZE size) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofSize(cx + size.cx, cy + size.cy);
}
inline CBofSize CBofSize::operator-(SIZE size) {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofSize(cx - size.cx, cy - size.cy);
}
inline CBofSize CBofSize::operator-() {
// Make sure object is not used after it is destructed
assert(isValidObject(this));
return CBofSize(-cx, -cy);
}
} // namespace Bagel
#endif

View File

@@ -0,0 +1,959 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "common/file.h"
#include "common/memstream.h"
#include "audio/mixer.h"
#include "audio/audiostream.h"
#include "audio/decoders/wave.h"
#include "bagel/bagel.h"
#include "bagel/boflib/sound.h"
#include "bagel/boflib/string_functions.h"
#include "bagel/boflib/event_loop.h"
#include "bagel/boflib/file_functions.h"
#include "bagel/boflib/log.h"
#include "bagel/music.h"
//#include "bagel/spacebar/boflib/app.h"
namespace Bagel {
#define MEMORY_THRESHOLD 20000L
#define MEMORY_MARGIN 100000L
char CBofSound::_szDrivePath[MAX_DIRPATH];
CBofSound *CBofSound::_pSoundChain = nullptr; // Pointer to chain of linked Sounds
int CBofSound::_nCount = 0; // Count of currently active Sounds
int CBofSound::_nWavCount = 1; // Available wave sound devices
int CBofSound::_nMidiCount = 1; // Available midi sound devices
void *CBofSound::_pMainWnd = nullptr; // Window for message processing
bool CBofSound::_bInit = false;
CQueue *CBofSound::_cQueue[NUM_QUEUES];
int CBofSound::_nSlotVol[NUM_QUEUES];
CBofSound::CBofSound() {
_wLoops = 1;
addToSoundChain();
}
CBofSound::CBofSound(void *pWnd, const char *pszPathName, uint16 wFlags, const int nLoops) {
_wLoops = (uint16)nLoops;
initialize(pWnd, pszPathName, wFlags);
addToSoundChain();
}
void CBofSound::addToSoundChain() {
// Insert this sound into the sound list
if (_pSoundChain != nullptr) {
_pSoundChain->Insert(this);
// _pSoundchain must always be the head of the list
assert(_pSoundChain == _pSoundChain->getHead());
} else {
_pSoundChain = this;
}
}
void CBofSound::initialize(void *pWnd, const char *pszPathName, uint16 wFlags) {
// Validate input
assert(pszPathName != nullptr);
assert(strlen(pszPathName) < MAX_FNAME);
//
// Initialize data fields
//
_pWnd = _pMainWnd;
if (pWnd != nullptr) {
_pWnd = pWnd;
if (_pMainWnd == nullptr)
_pMainWnd = pWnd;
}
_bPlaying = false; // Not yet playing
_bStarted = false;
_wFlags = wFlags; // Flags for playing
_bPaused = false; // Not suspended
_bExtensionsUsed = false; // No extended flags used.
_szFileName[0] = '\0';
_handle = {};
_pFileBuf = nullptr;
_nVol = VOLUME_INDEX_DEFAULT;
_bInQueue = false;
_iQSlot = 0;
for (int i = 0; i < NUM_QUEUES; i++) {
_nSlotVol[i] = VOLUME_INDEX_DEFAULT;
}
// Mixed assumes Asynchronous
if ((_wFlags & SOUND_MIX) == SOUND_MIX) {
_wFlags |= SOUND_ASYNCH;
}
if (_wFlags & SOUND_MIDI) {
_chType = g_engine->isSpaceBar() ?
SOUND_TYPE_XM : SOUND_TYPE_SMF;
} else {
_chType = SOUND_TYPE_WAV;
}
if (pszPathName != nullptr && (_wFlags & SND_MEMORY)) {
// In-memory wave sound
_pFileBuf = (byte *)const_cast<char *>(pszPathName);
_iFileSize = 999999;
} else if (pszPathName != nullptr) {
if ((_szDrivePath[0] != '\0') && (*pszPathName == '.'))
pszPathName++;
else if (!strncmp(pszPathName, ".\\", 2))
pszPathName += 2;
char szTempPath[MAX_DIRPATH];
snprintf(szTempPath, MAX_DIRPATH, "%s%s", _szDrivePath, pszPathName);
strreplaceStr(szTempPath, "\\\\", "\\");
strreplaceStr(szTempPath, "\\", "/");
// Continue as long as this file exists
if (fileExists(szTempPath)) {
fileGetFullPath(_szFileName, szTempPath);
if (!(_wFlags & SOUND_QUEUE)) {
if (_wFlags & SOUND_WAVE || _wFlags & SOUND_MIX) {
loadSound();
}
}
} else if (_wFlags & SOUND_MIDI) {
// Try both MIDI formats
strreplaceStr(szTempPath, ".MID", ".MOV");
if (fileExists(szTempPath)) {
fileGetFullPath(_szFileName, szTempPath);
_chType = SOUND_TYPE_QT;
} else {
reportError(ERR_FFIND, szTempPath);
}
} else {
reportError(ERR_FFIND, szTempPath);
}
}
}
CBofSound::~CBofSound() {
assert(isValidObject(this));
stop();
releaseSound();
if (this == _pSoundChain) { // special case head of chain
_pSoundChain = (CBofSound *)_pSoundChain->getNext();
}
}
void CBofSound::initialize() {
for (int i = 0; i < NUM_QUEUES; ++i)
_cQueue[i] = new CQueue();
resetQVolumes();
}
void CBofSound::resetQVolumes() {
// Set Q Volumes to default
for (int i = 0; i < NUM_QUEUES; i++) {
_nSlotVol[i] = VOLUME_INDEX_DEFAULT;
}
}
void CBofSound::shutdown() {
// Auto-delete any remaining sounds
clearSounds();
for (int i = 0; i < NUM_QUEUES; ++i)
delete _cQueue[i];
}
void CBofSound::setVolume(int nVolume) {
assert(nVolume >= VOLUME_INDEX_MIN && nVolume <= VOLUME_INDEX_MAX);
_nVol = CLIP(nVolume, VOLUME_INDEX_MIN, VOLUME_INDEX_MAX);
Audio::Mixer *mixer = g_system->getMixer();
byte vol = VOLUME_SVM(_nVol);
mixer->setChannelVolume(_handle, vol);
mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, vol);
mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol);
g_engine->_midi->setVolume(vol);
}
void CBofSound::setVolume(int nMidiVolume, int nWaveVolume) {
assert(nMidiVolume >= VOLUME_INDEX_MIN && nMidiVolume <= VOLUME_INDEX_MAX);
assert(nWaveVolume >= VOLUME_INDEX_MIN && nWaveVolume <= VOLUME_INDEX_MAX);
// Set master wave volume
int clippedVol = CLIP(nWaveVolume, VOLUME_INDEX_MIN, VOLUME_INDEX_MAX);
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, VOLUME_SVM(clippedVol));
// Set master Midi volume
clippedVol = CLIP(nMidiVolume, VOLUME_INDEX_MIN, VOLUME_INDEX_MAX);
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, VOLUME_SVM(clippedVol));
g_engine->_midi->setVolume(VOLUME_SVM(clippedVol));
}
bool CBofSound::play(uint32 dwBeginHere, uint32 TimeFormatFlag) {
assert(isValidObject(this));
// Assume success
bool bSuccess = true;
if (_errCode == ERR_NONE) {
// We must be attached to a valid window
assert((_pWnd != nullptr) || (_pMainWnd != nullptr));
// If already playing, then stop and start again
if (playing()) {
// Can't replay an autodelete sound
assert(!(_wFlags & SOUND_AUTODELETE));
stop();
}
// WAVE and MIX are mutually exclusive
assert(!((_wFlags & SOUND_WAVE) && (_wFlags & SOUND_MIX)));
if (_wFlags & SOUND_WAVE) {
if (_wFlags & SOUND_QUEUE)
waitWaveSounds();
else
stopWaveSounds();
} else if (_wFlags & SOUND_MIDI) {
if (_wFlags & SOUND_QUEUE)
waitMidiSounds();
else
stopMidiSounds();
}
// Make sure this sound is still valid
assert(_pSoundChain != nullptr);
if (_pFileBuf == nullptr) {
if ((_wFlags & (SOUND_MIX | SOUND_QUEUE)) == (SOUND_MIX | SOUND_QUEUE)) {
// Don't pre-load it
} else {
loadSound();
}
}
if (_wFlags & SOUND_MIDI) {
if (_wFlags & SOUND_LOOP)
_wLoops = 0;
g_engine->_midi->play(this);
_bPlaying = true;
} else if (_wFlags & SOUND_WAVE) {
playWAV();
if (_bPlaying) {
if (!(_wFlags & SOUND_ASYNCH)) {
EventLoop eventLoop;
auto *mixer = g_system->getMixer();
while (mixer->isSoundHandleActive(_handle)) {
if (eventLoop.frame()) {
stop();
break;
}
}
_handle = {};
_bPlaying = false;
}
}
} else if (_wFlags & SOUND_MIX) {
if (!(_wFlags & SOUND_QUEUE)) {
playWAV();
} else {
assert(_iQSlot >= 0 && _iQSlot < NUM_QUEUES);
_cQueue[_iQSlot]->addItem(this);
_bPlaying = true;
_bInQueue = true;
setVolume(_nSlotVol[_iQSlot]);
}
}
}
return bSuccess;
}
bool CBofSound::midiLoopPlaySegment(uint32 dwLoopFrom, uint32 dwLoopTo, uint32 dwBegin, uint32 TimeFmt) {
assert(isValidObject(this));
_wFlags |= SOUND_LOOP;
_wLoops = 0;
_dwRePlayStart = dwLoopFrom;
_dwRePlayEnd = dwLoopTo;
_bExtensionsUsed = true;
bool bSuccess = play(dwBegin, TimeFmt);
return bSuccess;
}
bool CBofSound::pauseSounds() {
bool bSuccess = true;
// Thumb through all the sounds
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) {
// If one is playing and not paused try to suspend it
if (pSound->playing() && (pSound->_bPaused == false)) {
bool bStatus = pSound->pause();
if (bStatus)
pSound->_bPaused = true;
else
bSuccess = false;
}
pSound = (CBofSound *)pSound->getNext();
}
return bSuccess;
}
bool CBofSound::pause() {
assert(isValidObject(this));
bool bSuccess = false;
// Must be playing to be paused and not already paused
if (playing() && (_bPaused == false)) {
bSuccess = true;
if (_wFlags & SOUND_MIDI) {
g_engine->_midi->pause();
} else {
g_system->getMixer()->pauseHandle(_handle, true);
}
}
if (bSuccess)
_bPaused = true;
return bSuccess;
}
bool CBofSound::resumeSounds() {
bool bSuccess = true;
CBofSound *pSound = _pSoundChain; // Thumb through all the sounds
while (pSound != nullptr) {
if (pSound->_bPaused) {
// If one is paused
bool bStatus = pSound->resume(); // ... try to get it going again
if (bStatus)
pSound->_bPaused = false; // success
else
bSuccess = false; // failure
}
pSound = (CBofSound *)pSound->getNext();
}
return bSuccess;
}
bool CBofSound::resume() {
assert(isValidObject(this));
bool bSuccess = false;
if (_bPaused) { // must be paused to resume
bSuccess = true;
if (_wFlags & SOUND_MIDI) {
g_engine->_midi->resume();
} else {
g_system->getMixer()->pauseHandle(_handle, false);
}
}
if (bSuccess)
_bPaused = false;
return bSuccess;
}
void CBofSound::stopSounds() {
CBofSound *pSound = _pSoundChain; // Thumb through all the sounds
while (pSound != nullptr) {
if (pSound->playing()) { // If one is playing
pSound->_bPaused = false; // ... its no longer paused
pSound->stop(); // Stop it
}
pSound = (CBofSound *)pSound->getNext();
}
}
void CBofSound::stopWaveSounds() {
CBofSound *pSound = _pSoundChain; // Find this Sound is the queue
while (pSound != nullptr) {
CBofSound *pNextSound = (CBofSound *)pSound->getNext();
if (pSound->playing() && ((pSound->_wFlags & SOUND_WAVE) || (pSound->_wFlags & SOUND_MIX))) {
pSound->stop();
if (pSound->_wFlags & SOUND_AUTODELETE)
delete pSound;
}
pSound = pNextSound;
}
}
void CBofSound::stopMidiSounds() {
CBofSound *pSound = _pSoundChain; // Find this Sound is the queue
while (pSound != nullptr) {
CBofSound *pNextSound = (CBofSound *)pSound->getNext();
if (pSound->playing() && (pSound->_wFlags & SOUND_MIDI)) {
pSound->stop();
if (pSound->_wFlags & SOUND_AUTODELETE)
delete pSound;
}
pSound = pNextSound;
}
}
void CBofSound::stop() {
assert(isValidObject(this));
// If this sound is currently playing
if (_wFlags & SOUND_MIDI) {
g_engine->_midi->stop();
} else {
g_system->getMixer()->stopHandle(_handle);
_handle = {};
}
if (_bInQueue) {
assert(_iQSlot >= 0 && _iQSlot < NUM_QUEUES);
_cQueue[_iQSlot]->deleteItem(this);
_bInQueue = false;
}
_bPlaying = false;
_bStarted = false;
_bPaused = false;
// One less audio playing
_nCount -= 1;
}
void CBofSound::clearSounds() {
stopSounds(); // Stop all active sounds
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) { // Delete all sound entries
CBofSound *pNextSound = pSound->getNext();
delete pSound;
pSound = pNextSound;
}
assert(_pSoundChain == nullptr);
}
void CBofSound::clearWaveSounds() {
CBofSound *pSound = _pSoundChain; // Find this Sound in the queue
while (pSound != nullptr) {
CBofSound *pNextSound = pSound->getNext();
if ((pSound->_wFlags & SOUND_WAVE) || (pSound->_wFlags & SOUND_MIX))
delete pSound;
pSound = pNextSound;
}
}
void CBofSound::clearMidiSounds() {
CBofSound *pSound = _pSoundChain; // find this Sound is the queue
while (pSound != nullptr) {
CBofSound *pNextSound = (CBofSound *)pSound->getNext();
if (pSound->_wFlags & SOUND_MIDI)
delete pSound;
pSound = pNextSound;
}
}
void CBofSound::waitSounds() {
waitWaveSounds();
waitMidiSounds();
}
void CBofSound::waitWaveSounds() {
uint32 dwTickCount = 0;
for (;;) {
audioTask();
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) {
if (pSound->playing() && (pSound->_wFlags & SOUND_WAVE || pSound->_wFlags & SOUND_MIX)) {
break;
}
pSound = (CBofSound *)pSound->getNext();
}
if (pSound == nullptr)
break;
if (handleMessages())
break;
// If 3 minutes go by, then just bolt
if (dwTickCount == 0)
dwTickCount = g_system->getMillis() + 1000 * 60 * 3;
if (g_system->getMillis() > dwTickCount) {
pSound->stop();
pSound->_bPlaying = false;
pSound->reportError(ERR_UNKNOWN, "CBofSound::waitWaveSounds() timeout!");
}
}
}
bool CBofSound::soundsPlaying() {
audioTask();
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) {
if (pSound->playing() && (pSound->_wFlags & SOUND_WAVE || pSound->_wFlags & SOUND_MIX)) {
return true;
}
pSound = (CBofSound *)pSound->getNext();
}
return false;
}
void CBofSound::waitMidiSounds() {
uint32 dwTickCount = 0;
for (;;) {
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) {
if (pSound->playing() && (pSound->_wFlags & SOUND_MIDI)) {
break;
}
pSound = (CBofSound *)pSound->getNext();
}
if (pSound == nullptr)
break;
if (handleMessages())
break;
if (dwTickCount == 0)
dwTickCount = g_system->getMillis() + 1000 * 60;
if (g_system->getMillis() > dwTickCount) {
pSound->stop();
pSound->reportError(ERR_UNKNOWN, "CBofSound::waitMidiSounds() timeout");
break;
}
}
}
bool CBofSound::handleMessages() {
if (g_engine->isSpaceBar()) {
Common::Event e;
while (g_system->getEventManager()->pollEvent(e)) {
}
g_system->delayMillis(10);
} else {
AfxGetApp()->pause();
}
return g_engine->shouldQuit();
}
bool CBofSound::bofSleep(uint32 wait) {
uint32 goal = wait + g_system->getMillis();
while (goal > g_system->getMillis()) {
if (handleMessages())
return true;
}
return false;
}
bool BofPlaySound(const char *pszSoundFile, uint32 nFlags, int iQSlot) {
// Assume failure
bool bSuccess;
if (pszSoundFile != nullptr) {
nFlags |= SOUND_AUTODELETE;
if (nFlags & SND_MEMORY) {
// Hardcoded for wave files
nFlags |= SOUND_WAVE;
} else if (!fileExists(pszSoundFile)) {
logWarning(buildString("Sound File '%s' not found", pszSoundFile));
return false;
}
// WORKAROUND: Hodj may not specify sound type
if (!(nFlags & (SOUND_WAVE | SOUND_MIDI))) {
Common::String name(pszSoundFile);
if (name.hasSuffixIgnoreCase(".wav"))
nFlags |= SOUND_WAVE;
else if (name.hasSuffixIgnoreCase(".mid"))
nFlags |= SOUND_MIDI;
}
// Take care of any last minute cleanup before we start this new sound
CBofSound::audioTask();
CBofSound::stopWaveSounds();
CBofSound *pSound = new CBofSound(/*pWnd*/nullptr, pszSoundFile, (uint16)nFlags);
if ((nFlags & SOUND_QUEUE) == SOUND_QUEUE) {
pSound->setQSlot(iQSlot);
}
bSuccess = pSound->play();
} else {
bSuccess = true;
CBofSound::stopWaveSounds();
}
return bSuccess;
}
bool BofPlaySoundEx(const char *pszSoundFile, uint32 nFlags, int iQSlot, bool bWait) {
// Assume failure
bool bSuccess = false;
if (pszSoundFile != nullptr) {
if ((nFlags & SOUND_MIX) == 0) {
bWait = false;
}
if (!bWait) {
nFlags |= SOUND_AUTODELETE;
}
if (!fileExists(pszSoundFile)) {
logWarning(buildString("Sound File '%s' not found", pszSoundFile));
return false;
}
//CBofWindow *pWnd = CBofApp::getApp()->getMainWindow();
// Take care of any last minute cleanup before we start this new sound
CBofSound::audioTask();
CBofSound *pSound = new CBofSound(/*pWnd*/nullptr, pszSoundFile, (uint16)nFlags);
if ((nFlags & SOUND_QUEUE) == SOUND_QUEUE) {
pSound->setQSlot(iQSlot);
}
bSuccess = pSound->play();
if (bWait) {
while (pSound->isPlaying()) {
CBofSound::audioTask();
}
delete pSound;
}
}
return bSuccess;
}
bool CBofSound::loadSound() {
assert(isValidObject(this));
assert(_szFileName[0] != '\0');
bool bSuccess = true;
if (_pFileBuf == nullptr) {
bSuccess = false;
Common::File in;
if (in.open(_szFileName)) {
_iFileSize = in.size();
_pFileBuf = (byte *)malloc(_iFileSize);
if (in.read(_pFileBuf, _iFileSize) == _iFileSize)
bSuccess = true;
}
}
return bSuccess;
}
bool CBofSound::releaseSound() {
assert(isValidObject(this));
if (!(_wFlags & SND_MEMORY))
free(_pFileBuf);
_pFileBuf = nullptr;
return true;
}
bool CBofSound::soundsPlayingNotOver() {
// Assume no wave sounds are playing
bool bPlaying = false;
// Walk through sound list, and check for sounds that need attention
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) {
if (pSound->playing() &&
(pSound->_wFlags & SOUND_WAVE || pSound->_wFlags & SOUND_MIX) &&
!(pSound->_wFlags & SOUND_OVEROK)) {
bPlaying = true;
break;
}
pSound = (CBofSound *)pSound->getNext();
}
return bPlaying;
}
bool CBofSound::waveSoundPlaying() {
// Assume no wave sounds are playing
bool bPlaying = false;
// Walk through sound list, and check for sounds that need attention
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) {
if (pSound->playing() && (pSound->_wFlags & SOUND_WAVE || pSound->_wFlags & SOUND_MIX)) {
bPlaying = true;
break;
}
pSound = (CBofSound *)pSound->getNext();
}
return bPlaying;
}
bool CBofSound::midiSoundPlaying() {
// Assume no wave sounds are playing
bool bPlaying = false;
// Walk through sound list, and check for sounds that need attention
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) {
if (pSound->playing() && (pSound->_wFlags & SOUND_MIDI)) {
bPlaying = true;
break;
}
pSound = (CBofSound *)pSound->getNext();
}
return bPlaying;
}
void CBofSound::audioTask() {
static bool bAlready = false;
// Don't allow recursion here
assert(!bAlready);
bAlready = true;
// Walk through sound list, and check for sounds that need attention
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) {
if (!pSound->paused()) {
if ((pSound->_wFlags & SOUND_WAVE) || (pSound->_wFlags & SOUND_MIX)) {
// Has this sound been played?
if (pSound->_bStarted) {
// And, Is it done?
if (!g_system->getMixer()->isSoundHandleActive(pSound->_handle)) {
// Kill it
pSound->stop();
}
} else if (pSound->_bInQueue) {
// If this is a Queued sound, and has not already started
// And it is time to play
if ((CBofSound *)_cQueue[pSound->_iQSlot]->getQItem() == pSound) {
pSound->playWAV();
}
}
} else if ((pSound->_wFlags & SOUND_MIDI) && pSound->_bPlaying) {
// And, Is it done?
if (!g_engine->_midi->isPlaying()) {
// Kill it
pSound->stop();
}
}
}
pSound = (CBofSound *)pSound->getNext();
}
bAlready = false;
}
ErrorCode CBofSound::playWAV() {
assert(isValidObject(this));
if (!errorOccurred()) {
// If it's not yet loaded, then load it now
if (_pFileBuf == nullptr) {
loadSound();
}
assert(_pFileBuf != nullptr);
if (_pFileBuf != nullptr) {
if (_bInQueue) {
setVolume(_nSlotVol[_iQSlot]);
}
// Then, Play it
Common::SeekableReadStream *stream = new Common::MemoryReadStream(_pFileBuf, _iFileSize);
Audio::AudioStream *audio = Audio::makeLoopingAudioStream(Audio::makeWAVStream(stream, DisposeAfterUse::YES), _wLoops);
if (audio == nullptr) {
reportError(ERR_UNKNOWN, "Could not allocate audio stream.");
}
g_system->getMixer()->playStream(Audio::Mixer::kSFXSoundType, &_handle, audio, -1, VOLUME_SVM(_nVol));
_bPlaying = true;
_bStarted = true;
}
}
return _errCode;
}
ErrorCode CBofSound::flushQueue(int nSlot) {
assert(nSlot >= 0 && nSlot < NUM_QUEUES);
// Assume no error
ErrorCode errorCode = ERR_NONE;
// Remove all queued sounds
_cQueue[nSlot]->flush();
// Including any that are currently playing
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) {
// Prefetch next sound in case stop() deletes this one
CBofSound *pNextSound = pSound->getNext();
// If this sound is playing from specified queue
if (pSound->isPlaying() && pSound->_bInQueue && pSound->_iQSlot == nSlot) {
// Then chuck it
pSound->stop();
}
// Next
pSound = pNextSound;
}
return errorCode;
}
void CBofSound::setQVol(int nSlot, int nVol) {
// Validate input
assert(nSlot >= 0 && nSlot < NUM_QUEUES);
assert(nVol >= 0 && nVol <= VOLUME_INDEX_MAX);
_nSlotVol[nSlot] = nVol;
// Set all Queued sounds in specified slot to this volume
CBofSound *pSound = _pSoundChain;
while (pSound != nullptr) {
if (pSound->_bInQueue && pSound->_iQSlot == nSlot) {
pSound->setVolume(nVol);
}
pSound = pSound->getNext();
}
}
bool MessageBeep(int uType) {
warning("TODO: beep");
return true;
}
} // namespace Bagel

View File

@@ -0,0 +1,247 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/".
*
*/
#ifndef BAGEL_BOFLIB_SOUND_H
#define BAGEL_BOFLIB_SOUND_H
#include "audio/mixer.h"
#include "bagel/boflib/stdinc.h"
#include "bagel/boflib/llist.h"
#include "bagel/boflib/object.h"
#include "bagel/boflib/error.h"
#include "bagel/boflib/queue.h"
namespace Bagel {
//
// Wavemix-related constants
//
#define VOLUME_INDEX_MIN 0
#define VOLUME_INDEX_MAX 12
#define VOLUME_INDEX_DEFAULT 10
// Convert to ScummVM scale
#define VOLUME_SVM(x) ((x) * Audio::Mixer::kMaxChannelVolume / VOLUME_INDEX_MAX)
#define SVM_VOLUME(x) (((x) >= 252) ? VOLUME_INDEX_MAX : (x) * VOLUME_INDEX_MAX / 252)
#define SOUND_BUFFERED 0x0001
#define SOUND_ASYNCH 0x0002
#define SOUND_NOTIFY 0x0004
#define SOUND_AUTODELETE 0x0008
#define SOUND_LOOP 0x0010
#define SOUND_WAVE 0x0020
#define SOUND_MIDI 0x0040
#define SOUND_DONT_LOOP_TO_END 0x0080
#define SOUND_QUEUE 0x0100 // With wavemix: play after previous sound finishes
#define SOUND_MIX 0x0200 // Use wavemix to really play asynchronously
#define SOUND_ASAP 0x0400 // Play as soon as a channel is free (maybe now)
#define SOUND_WAIT 0x0800 // For wavemix: Set sound up but don't play it yet
#define SOUND_LOCK 0x1000 // Reserve this channel until user stops it
#define SOUND_PRELOAD 0x2000 // Only works for Resource MAC snd files
#define SOUND_OVEROK 0x4000 // OK to play another sound over this file
#define SND_MEMORY 0x8000 // Raw in-memory sound passed rather than a filename
#define SND_NODEFAULT 0
#define SND_SYNC 0
#define SND_ASYNC SOUND_ASYNCH
#define SOUND_TYPE_WAV 1
#define SOUND_TYPE_XM 2
#define SOUND_TYPE_QT 3
#define SOUND_TYPE_SMF 4
#define FMT_MILLISEC 1 // Time format specifiers.
#define FMT_BPM 2
#define NUM_QUEUES 8
class CBofSound : public CBofError, public CBofObject, public CLList {
public:
friend class MusicPlayer;
CBofSound();
CBofSound(void *pWnd, const char *pszPathName, uint16 wFlags, int nLoops = 1);
virtual ~CBofSound();
void addToSoundChain();
void initialize(const char *pszPathName, uint16 wFlags) {
initialize(nullptr, pszPathName, wFlags);
}
void initialize(void *pWnd, const char *pszPathName, uint16 wFlags);
void setDrivePath(const char *path) {}
bool midiLoopPlaySegment(uint32 LoopBegin, uint32 LoopEnd = 0L, uint32 FirstPassBegin = 0L, uint32 TimeFmt = FMT_MILLISEC);
bool play(uint32 StartOfPlay = 0L, uint32 TimeFmtFlag = FMT_MILLISEC);
bool pause();
bool resume();
void stop();
CBofSound *getNext() {
return (CBofSound *)_pNext;
}
CBofSound *getPrev() {
return (CBofSound *)_pPrev;
}
char *getFileName() {
return &_szFileName[0];
}
void setFlags(uint16 wFlags) {
_wFlags = wFlags;
}
uint16 getFlags() {
return _wFlags;
}
bool playing() {
return isPlaying();
}
bool isPlaying() {
return _bPlaying;
}
bool isQueued() {
return _bInQueue;
}
bool paused() {
return _bPaused;
}
void setQSlot(int nSlot) {
_iQSlot = nSlot;
}
int getQSlot() {
return _iQSlot;
}
void setVolume(int nVol);
int getVolume() {
return _nVol;
}
static void initialize();
static void shutdown();
static void setVolume(int MidiVolume, int WaveVolume);
static bool soundPlaying() {
return (_nCount > 0) ? true : false;
}
static bool waveSoundPlaying();
static bool midiSoundPlaying();
static bool soundsPlayingNotOver();
static void setQVol(int nSlot, int nVol);
ErrorCode playWAV();
static ErrorCode flushQueue(int nSlot);
static void resetQVolumes();
static bool pauseSounds();
static bool resumeSounds();
static void stopSounds();
static void stopWaveSounds();
static void stopMidiSounds();
static void clearSounds();
static void clearWaveSounds();
static void clearMidiSounds();
static void waitSounds();
static void waitWaveSounds();
static void waitMidiSounds();
static bool handleMessages();
static bool bofSleep(uint32 dwTime);
static void audioTask();
static bool soundsPlaying();
static bool MidiAvailable() {
return true;
}
static bool SoundAvailable() {
return true;
}
static bool SoundVolumeAvailable() {
return true;
}
static bool MidiVolumeAvailable() {
return true;
}
static CBofSound *OnMCIStopped(WPARAM wParam, LPARAM lParam) {
return nullptr;
}
static CBofSound *OnMMIOStopped(WPARAM wParam, LPARAM lParam) {
return nullptr;
}
private:
bool loadSound();
bool releaseSound();
private:
char _szFileName[MAX_FNAME]; // Path spec for sound file
int8 _chType = 0; // Type of sound commands used
uint16 _wLoops = 0; // Number of times to loop the sound (0xFFFF means infinite)
uint16 _wFlags = 0; // Flags for playing
bool _bPaused = false; // Whether its paused
bool _bPlaying = false; // Whether its playing
bool _bExtensionsUsed = false;
uint32 _dwPlayStart = 0;
uint32 _dwRePlayStart = 0;
uint32 _dwRePlayEnd = 0;
Audio::SoundHandle _handle;
byte *_pFileBuf = nullptr;
uint32 _iFileSize = 0;
int _iQSlot = 0;
bool _bInQueue = false;
bool _bStarted = false;
int _nVol = 0;
void *_pWnd = nullptr; // Parent window for messages
static char _szDrivePath[MAX_DIRPATH]; // Path spec to drive
static CBofSound *_pSoundChain; // First item in chain or nullptr
static int _nCount; // Count of active sounds
static int _nWavCount; // Number of wave sound devices
static int _nMidiCount; // Number of midi sound devices
static void *_pMainWnd; // Window for message processing
static bool _bInit;
static int _nSlotVol[NUM_QUEUES];
static CQueue *_cQueue[NUM_QUEUES];
};
#define CSound CBofSound
extern bool BofPlaySound(const char *pszSoundFile, uint32 nFlags, int iQSlot = 0);
extern bool BofPlaySoundEx(const char *pszSoundFile, uint32 nFlags, int iQSlot = 0, bool bWait = false);
extern bool MessageBeep(int uType);
#define sndPlaySound BofPlaySound
} // namespace Bagel
#endif

View File

@@ -0,0 +1,95 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_STDINC_H
#define BAGEL_BOFLIB_STDINC_H
#include "common/scummsys.h"
#include "common/rect.h"
#include "bagel/afxwin.h"
namespace Bagel {
/*
* Normal types
*/
typedef void *(*BofCallback)(int, void *);
typedef long Fixed;
/*
* Extended types
*/
struct StSize {
int cx;
int cy;
};
struct StPoint {
int x;
int y;
};
struct Vector {
double x;
double y;
double z;
};
struct WindowPos {
void *hwnd = nullptr;
void *hwndinsertAfter = nullptr;
int x = 0;
int y = 0;
int cx = 0;
int cy = 0;
uint32 flags = 0;
};
#define MAKE_WORD(a, b) ((uint16)(((byte)(a)) | ((uint16)((byte)(b))) << 8))
#define MAKE_LONG(low, high) ((int32)(((uint16)(low)) | (((uint32)((uint16)(high))) << 16)))
/* For big-endian platforms (i.e. MAC) */
#define SWAPWORD(x) MAKE_WORD(HIBYTE(x), LOBYTE(x))
#define SWAPLONG(x) MAKE_LONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
#ifndef MAX_FNAME
#define MAX_FNAME 256
#endif
#define MAX_DIRPATH 256
#ifndef PDFT
#define PDFT(VALUE) = VALUE
#endif
/*
* normal types
*/
#define VIRTUAL virtual
#define STATIC static
#define CDECL
#define INLINE inline
} // namespace Bagel
#endif

View File

@@ -0,0 +1,599 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/str.h"
#include "bagel/boflib/string.h"
#include "bagel/boflib/misc.h"
#include "bagel/boflib/string_functions.h"
namespace Bagel {
#define MAX_STRING 256
#define BUF_EXTRA 20
CBofString::CBofString() {
init();
}
CBofString::CBofString(int nLength) {
init();
allocBuffer(nLength);
}
CBofString::CBofString(const CBofString &cString) {
init();
copy(cString._pszData);
}
CBofString::CBofString(const char *pszBuf) {
init();
copy(pszBuf);
}
CBofString::CBofString(char *pszBuff, int pszBuffLen) {
init();
// Force a max length (To stop uninitialized buffer from killing us)
*(pszBuff + pszBuffLen - 1) = '\0';
// Passing in un-initialized data could cause problems depending on what
// string functions are used after this constructor.
_nLength = (uint16)strlen(pszBuff);
// Use the high byte of the buffer size to determine if we're using stack memory.
// Make sure that we don't have an obscenely large string
assert((pszBuffLen & mUseStackMem) == false);
SETBUFFERSIZE(pszBuffLen, true);
_pszData = pszBuff;
}
CBofString::CBofString(char ch, int nRepeat) {
assert(nRepeat > 0);
init();
allocBuffer(nRepeat);
memset(_pszData, ch, nRepeat);
}
CBofString::~CBofString() {
assert(isValidObject(this));
free();
}
void CBofString::init() {
assert(isValidObject(this));
SETBUFFERSIZE(0, false);
_nLength = 0;
_pszData = nullptr;
}
void CBofString::allocBuffer(int nLen) {
assert(isValidObject(this));
assert(nLen >= 0);
// These 3 lines "should" do the same thing
assert(nLen < SHRT_MAX); // max size (enough room for 1 extra)
assert((uint16)nLen < mUseStackMem);
assert((nLen & mUseStackMem) == 0);
// Delete any previous buffer
free();
// Don't do anything about zero length allocations
if (nLen > 0) {
// Allocate a buffer filled with 0s
_pszData = (char *)bofCleanAlloc(nLen + 1);
}
_nLength = 0;
// Use the high byte of the bufflen to indicate if we're using
// stack mem or not. Make sure our buff size is not too big
assert((nLen & mUseStackMem) == 0);
SETBUFFERSIZE(nLen, false);
}
void CBofString::free() {
assert(isValidObject(this));
bool bStackMem = USESSTACKMEM();
// Free any attached data
// Only free if it's not stack memory
if (_pszData != nullptr && bStackMem == false) {
bofFree(_pszData);
_pszData = nullptr;
}
_nLength = 0;
SETBUFFERSIZE(0, bStackMem);
}
void CBofString::copy(const char *pszBuf) {
assert(isValidObject(this));
if (NORMALIZEBUFFERSIZE() != 0)
*_pszData = '\0';
_nLength = 0;
if (pszBuf != nullptr) {
int n = strlen(pszBuf);
if (NORMALIZEBUFFERSIZE() <= n) {
allocBuffer(n + 1);
}
Common::strcpy_s(_pszData, n + 1, pszBuf);
_nLength = (uint16)strlen(_pszData);
}
}
void CBofString::allocCopy(CBofString &dest, int nCopyLen, int nCopyIndex, int nExtraLen) const {
assert(isValidObject(this));
// Will clone the data attached to this string allocating 'nExtraLen' characters
// Places results in uninitialized string 'dest'
// Will copy the part or all of original data to start of new string
int nNewLen = nCopyLen + nExtraLen;
if (nNewLen == 0) {
dest.free();
} else {
dest.allocBuffer(nNewLen);
assert(_pszData != nullptr);
memcpy(dest._pszData, &_pszData[nCopyIndex], nCopyLen * sizeof(char));
}
}
const CBofString &CBofString::operator=(const CBofString &cString) {
assert(isValidObject(this));
copy(cString._pszData);
return *this;
}
const CBofString &CBofString::operator=(const char *lpsz) {
assert(isValidObject(this));
copy(lpsz);
return *this;
}
void CBofString::concatCopy(int nSrc1Len, const char *lpszSrc1Data, int nSrc2Len, const char *lpszSrc2Data, int nAllocLen) {
assert(isValidObject(this));
// -- Master concatenation routine
// concatenate two sources
// -- Assume that 'this' is a new CBofString object
int nNewLen = nSrc1Len + nSrc2Len;
allocBuffer((nAllocLen == 0 ? nNewLen : nAllocLen));
memcpy(_pszData, lpszSrc1Data, nSrc1Len * sizeof(char));
memcpy(&_pszData[nSrc1Len], lpszSrc2Data, nSrc2Len * sizeof(char));
// RMS
_nLength = (uint16)nNewLen;
}
CBofString operator+(const CBofString &string1, const CBofString &string2) {
CBofString s;
s.concatCopy(string1._nLength, string1._pszData, string2._nLength, string2._pszData);
return s;
}
CBofString operator+(const CBofString &string, const char *lpsz) {
CBofString s;
s.concatCopy(string._nLength, string._pszData, CBofString::safeStrlen(lpsz), lpsz);
return s;
}
CBofString operator+(const char *lpsz, const CBofString &string) {
CBofString s;
s.concatCopy(CBofString::safeStrlen(lpsz), lpsz, string._nLength, string._pszData);
return s;
}
void CBofString::concatInPlace(int nSrcLen, const char *lpszSrcData) {
char szLocalBuff[512];
assert(isValidObject(this));
// -- The main routine for += operators
// If the buffer is too small, or we have a width mis-match, just
// allocate a new buffer (slow but sure)
//
// Make sure we have an underlying buffer.
if (_nLength + nSrcLen >= NORMALIZEBUFFERSIZE()) {
// Don't increment by buf extra, but set the size if we're
// less than that default threshold.
int nAllocAmount = nSrcLen;
if (nAllocAmount < BUF_EXTRA) {
nAllocAmount = BUF_EXTRA;
}
if (NORMALIZEBUFFERSIZE() == 0) {
allocBuffer(_nLength + nAllocAmount);
memcpy(_pszData, lpszSrcData, nSrcLen);
*(_pszData + nSrcLen) = '\0';
_nLength = (uint16)(_nLength + (uint16)nSrcLen);
} else {
assert(_pszData != nullptr);
// We have to grow the buffer, use the concat in place routine
char *lpszOldData;
if ((_nLength + nSrcLen + 1) < 512)
lpszOldData = szLocalBuff;
else
lpszOldData = new char[_nLength + nSrcLen + 1];
memcpy(lpszOldData, _pszData, (_nLength + 1) * sizeof(char));
concatCopy(_nLength, lpszOldData, nSrcLen, lpszSrcData, _nLength + nAllocAmount);
if (lpszOldData != szLocalBuff)
delete[] lpszOldData;
}
} else {
// Fast concatenation when buffer big enough
// Optimize for a single byte
if (nSrcLen == 1) {
_pszData[_nLength] = *lpszSrcData;
} else {
memcpy(&_pszData[_nLength], lpszSrcData, nSrcLen * sizeof(char));
}
_nLength = (uint16)(_nLength + (uint16)nSrcLen);
}
assert(_nLength <= NORMALIZEBUFFERSIZE());
_pszData[_nLength] = '\0';
}
const CBofString &CBofString::operator+=(const char *lpsz) {
assert(isValidObject(this));
concatInPlace(safeStrlen(lpsz), lpsz);
return *this;
}
const CBofString &CBofString::operator+=(char ch) {
assert(isValidObject(this));
concatInPlace(1, &ch);
return *this;
}
const CBofString &CBofString::operator+=(const CBofString &string) {
assert(isValidObject(this));
concatInPlace(string._nLength, string._pszData);
return *this;
}
char *CBofString::getBuffer() {
assert(isValidObject(this));
if (_pszData == nullptr) {
allocBuffer(1);
}
return _pszData;
}
int CBofString::findNumOccurrences(const char *pszSub) {
assert(isValidObject(this));
assert(pszSub != nullptr);
assert(*pszSub != '\0');
int nHits = 0;
if (_pszData != nullptr) {
char *pszCur = _pszData;
while (pszCur != nullptr) {
pszCur = strstr(pszCur, pszSub);
if (pszCur != nullptr) {
nHits++;
pszCur++;
}
}
}
return nHits;
}
const CBofString &CBofString::operator=(char ch) {
assert(isValidObject(this));
char szBuf[4];
Common::sprintf_s(szBuf, "%c", ch);
copy(szBuf);
return *this;
}
CBofString operator+(const CBofString &string1, char ch) {
CBofString s;
s.concatCopy(string1._nLength, string1._pszData, 1, &ch);
return s;
}
CBofString operator+(char ch, const CBofString &string) {
CBofString s;
s.concatCopy(1, &ch, string._nLength, string._pszData);
return s;
}
CBofString CBofString::mid(int nFirst) const {
assert(isValidObject(this));
return mid(nFirst, _nLength - nFirst);
}
CBofString CBofString::mid(int nFirst, int nCount) const {
assert(isValidObject(this));
assert(nFirst >= 0);
assert(nCount >= 0);
// Out-of-bounds requests return sensible things
if (nFirst + nCount > _nLength)
nCount = _nLength - nFirst;
if (nFirst > _nLength)
nCount = 0;
CBofString dest;
allocCopy(dest, nCount, nFirst, 0);
return dest;
}
CBofString CBofString::right(int nCount) const {
assert(isValidObject(this));
assert(nCount >= 0);
if (nCount > _nLength)
nCount = _nLength;
CBofString dest;
allocCopy(dest, nCount, _nLength - nCount, 0);
return dest;
}
CBofString CBofString::left(int nCount) const {
assert(isValidObject(this));
assert(nCount >= 0);
if (nCount > _nLength)
nCount = _nLength;
CBofString dest;
allocCopy(dest, nCount, 0, 0);
return dest;
}
void CBofString::deleteLastChar() {
if (!isEmpty()) {
*(_pszData + _nLength - 1) = '\0';
--_nLength;
}
}
// Find a sub-string (like strstr)
int CBofString::find(const char *lpszSub) const {
assert(isValidObject(this));
// Find first matching substring
char *lpsz = nullptr;
if (_pszData != nullptr)
lpsz = strstr(_pszData, lpszSub);
// Return -1 for not found, distance from beginning otherwise
return (lpsz == nullptr) ? -1 : (int)(lpsz - _pszData);
}
// CBofString formatting
#define FORCE_ANSI 0x10000
#define FORCE_UNICODE 0x20000
int CBofString::safeStrlen(const char *psz) {
return (psz == nullptr) ? 0 : strlen(psz);
}
// CBofString support (windows specific)
//
int CBofString::compare(const char *psz) const {
assert(isValidObject(this));
assert(psz != nullptr);
int n = -1;
if (_pszData != nullptr)
n = strcmp(_pszData, psz);
return n;
}
int CBofString::compareNoCase(const char *psz) const {
assert(isValidObject(this));
int n = -1;
if (_pszData != nullptr)
n = scumm_stricmp(_pszData, psz);
return n;
}
char CBofString::getAt(int nIndex) {
assert(isValidObject(this));
assert(nIndex >= 0);
assert(nIndex < _nLength);
return _pszData[nIndex];
}
char CBofString::operator[](int nIndex) {
assert(isValidObject(this));
return getAt(nIndex);
}
void CBofString::replaceCharAt(int nIndex, char chNew) {
if (_pszData != nullptr && nIndex < _nLength) {
_pszData[nIndex] = chNew;
}
}
void CBofString::replaceChar(char chOld, char chNew) {
assert(isValidObject(this));
// Would never find the terminator
assert(chOld != '\0');
if (_pszData != nullptr) {
// Walk through the string and replace the specified character
char *p = _pszData;
for (int i = 0; i < _nLength; i++) {
if (*p == chOld) {
*p = chNew;
// If we just inserted the terminator, then the length of
// this string has been changed, and we don't have to search
// any more.
//
if (chNew == '\0') {
_nLength = (uint16)i;
break;
}
}
p++;
}
}
}
void CBofString::replaceStr(const char *pszOld, const char *pszNew) {
assert(isValidObject(this));
assert(pszOld != nullptr);
assert(pszNew != nullptr);
if (_pszData != nullptr) {
char *p, *pszSearch;
int nOldLen = strlen(pszOld);
int nNewLen = strlen(pszNew);
// 1st pass to determine how much more storage space we might need
if (nNewLen > nOldLen) {
int nDiff = nNewLen - nOldLen;
int nNeedLength = _nLength + 1;
p = _pszData;
pszSearch = strstr(p, pszOld);
while (pszSearch != nullptr) {
p = pszSearch + nOldLen;
nNeedLength += nDiff;
pszSearch = strstr(p, pszOld);
}
// If we need more storage space for the buffer, then get some
if (nNeedLength > NORMALIZEBUFFERSIZE()) {
growTo(nNeedLength);
}
}
// Loop on the search and replace
// Make sure we loop on this, not just once as we can have several occurrences
// of the token that we are searching for.
p = _pszData;
pszSearch = strstr(p, pszOld);
while (pszSearch != nullptr) {
strreplaceStr(p, pszOld, pszNew);
p = pszSearch + nNewLen;
pszSearch = strstr(p, pszOld);
}
// Get new length
_nLength = (uint16)strlen(_pszData);
}
}
void CBofString::growTo(int nNewSize) {
assert(isValidObject(this));
// If there is nothing in the buffer to save, then just allocate what
// is needed
if (_nLength == 0) {
allocBuffer(nNewSize);
} else {
// Otherwise, we must keep track of whats in the buffer
// Create a temp buffer to save string
char *p = (char *)bofAlloc(_nLength + 2);
// Save copy of string
Common::strcpy_s(p, MAX_STRING, _pszData);
// Make the new buffer
allocBuffer(nNewSize);
// Copy saved string back
strncpy(_pszData, p, nNewSize - 1);
// Get it's new length
_nLength = (uint16)strlen(_pszData);
// Don't need temp buffer anymore
bofFree(p);
}
}
int CBofString::hash() const {
int returnValue = 0;
// Needs to be case in-sensitive
for (int i = 0; i < _nLength; i++) {
returnValue = returnValue + (char)toupper(_pszData[i]);
}
return returnValue;
}
void CBofString::makeUpper() {
Common::String s(_pszData);
s.toUppercase();
strncpy(_pszData, s.c_str(), _nLength);
}
} // namespace Bagel

View File

@@ -0,0 +1,274 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_STRING_H
#define BAGEL_BOFLIB_STRING_H
#include "common/system.h"
#include "bagel/boflib/object.h"
namespace Bagel {
// The buffer size and string len members are shorts, and use the high byte
// of the buffer size to tell us if it is stack memory being used.
#define mUseStackMem 0x8000
#define NORMALIZEBUFFERSIZE() (_nBufferSize & ~mUseStackMem)
#define SETBUFFERSIZE(size, usestackmem) (_nBufferSize = (uint16)((size) + ((usestackmem) ? mUseStackMem : 0)))
#define USESSTACKMEM() (_nBufferSize & mUseStackMem)
class CBofString : public CBofObject {
public:
// Constructors
/**
* Default constructor
*/
CBofString();
/**
* Construct a string from a null terminated string
* @param pszBuf Source string
*/
CBofString(const char *pszBuf);
/**
* Construct a string based on a source string
*/
CBofString(const CBofString &stringSrc);
/**
* Construct a string with a single character repeated a number of times
* @param ch Character to use
* @param nRepeat Number of repeats
*/
CBofString(char ch, int nRepeat = 1);
/**
* Constructs a string, and sets initial buffer size
* @param nLength String length
*/
CBofString(int nLength);
/**
* Construct a string based on a subset of a passed null terminated string
* @brief This modifies the passed source string to null terminate the substring
* @param pszBuff Source string
* @param pszBuffLen Substring length
*/
CBofString(char *pszBuff, int pszBuffLen);
/**
* Destructor
*/
virtual ~CBofString();
// Attributes & Operations
int getBufferSize() const {
return NORMALIZEBUFFERSIZE();
}
int getLength() const {
return _nLength;
}
bool isEmpty() const {
return _nLength == 0;
}
/**
* De-Allocates internal buffer for current CBofString
*/
void free();
void growTo(int nNewSize); // Resize the buffer
char getAt(int nIndex); // 0 based
char operator[](int nIndex); // same as getAt
operator const char *() const {
return (const char *)_pszData;
}
const char *getBuffer() const {
return _pszData;
}
// Hashing support.
//
int hash() const;
// Overloaded assignment
/**
* Copies specified string into current CBofString
* @param pszSourceBuf Buffer to copy
*/
void copy(const char *pszSourceBuf);
const CBofString &operator=(const CBofString &cStringSrc);
const CBofString &operator=(char ch);
const CBofString &operator=(const char *psz);
// String concatenation
const CBofString &operator+=(const CBofString &cString);
const CBofString &operator+=(char ch);
const CBofString &operator+=(const char *psz);
friend CBofString operator+(const CBofString &string1, const CBofString &string2);
friend CBofString operator+(const CBofString &string, char ch);
friend CBofString operator+(char ch, const CBofString &string);
friend CBofString operator+(const CBofString &string, const char *lpsz);
friend CBofString operator+(const char *lpsz, const CBofString &string);
// String comparison
int compare(const char *lpsz) const; // straight character
int compareNoCase(const char *lpsz) const; // ignore case
// Simple sub-string extraction
//
CBofString mid(int nFirst, int nCount) const;
CBofString mid(int nFirst) const;
CBofString left(int nCount) const;
CBofString right(int nCount) const;
void deleteLastChar();
// Upper/lower/reverse conversion
void makeUpper();
// Searching (return starting index, or -1 if not found)
// Look for a specific sub-string
int find(const char *lpszSub) const; // like "C" strstr
int findNumOccurrences(const char *pszSub);
// Search and replace routines
void replaceCharAt(int, char);
void replaceChar(char chOld, char chNew);
void replaceStr(const char *pszOld, const char *pszNew);
// Access to string implementation buffer as "C" character array
char *getBuffer();
protected:
// implementation helpers
/**
* initialize current CBofString members
*/
void init();
/**
* Allocates specified string into specified destination
*/
void allocCopy(CBofString &dest, int nCopyLen, int nCopyIndex, int nExtraLen) const;
/**
* Allocates internal buffer for current CBofString
* @param nLen Initial buffer size
*/
void allocBuffer(int nLen);
void concatCopy(int nSrc1Len, const char *lpszSrc1Data, int nSrc2Len, const char *lpszSrc2Data, int nAllocLen = 0);
void concatInPlace(int nSrcLen, const char *lpszSrcData);
static int safeStrlen(const char *lpsz);
// Lengths/sizes in characters
// (note: an extra character is always allocated)
//
char *_pszData; // actual string (zero terminated)
uint16 _nLength; // does not include terminating 0
uint16 _nBufferSize; // does not include terminating 0
};
// Inline Comparison operators
//
inline bool operator==(const CBofString &s1, const CBofString &s2) {
return s1.compare(s2) == 0;
}
inline bool operator==(const CBofString &s1, const char *s2) {
return s1.compare(s2) == 0;
}
inline bool operator==(const char *s1, const CBofString &s2) {
return s2.compare(s1) == 0;
}
inline bool operator!=(const CBofString &s1, const CBofString &s2) {
return s1.compare(s2) != 0;
}
inline bool operator!=(const CBofString &s1, const char *s2) {
return s1.compare(s2) != 0;
}
inline bool operator!=(const char *s1, const CBofString &s2) {
return s2.compare(s1) != 0;
}
inline bool operator<(const CBofString &s1, const CBofString &s2) {
return s1.compare(s2) < 0;
}
inline bool operator<(const CBofString &s1, const char *s2) {
return s1.compare(s2) < 0;
}
inline bool operator<(const char *s1, const CBofString &s2) {
return s2.compare(s1) > 0;
}
inline bool operator>(const CBofString &s1, const CBofString &s2) {
return s1.compare(s2) > 0;
}
inline bool operator>(const CBofString &s1, const char *s2) {
return s1.compare(s2) > 0;
}
inline bool operator>(const char *s1, const CBofString &s2) {
return s2.compare(s1) < 0;
}
inline bool operator<=(const CBofString &s1, const CBofString &s2) {
return s1.compare(s2) <= 0;
}
inline bool operator<=(const CBofString &s1, const char *s2) {
return s1.compare(s2) <= 0;
}
inline bool operator<=(const char *s1, const CBofString &s2) {
return s2.compare(s1) >= 0;
}
inline bool operator>=(const CBofString &s1, const CBofString &s2) {
return s1.compare(s2) >= 0;
}
inline bool operator>=(const CBofString &s1, const char *s2) {
return s1.compare(s2) >= 0;
}
inline bool operator>=(const char *s1, const CBofString &s2) {
return s2.compare(s1) <= 0;
}
} // namespace Bagel
#endif

View File

@@ -0,0 +1,98 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/str.h"
#include "bagel/boflib/string_functions.h"
namespace Bagel {
int strCharCount(const char *str, char c) {
assert(str != nullptr);
int n = 0;
while (*str != '\0') {
if (*str++ == c)
n++;
}
return n;
}
char *strreplaceChar(char *str, char cOld, char cNew) {
char *p = str;
// Can't access a nullptr pointer
assert(str != nullptr);
// If cOld was '\0' then this function would do nothing
assert(cOld != '\0');
while (*p != '\0') {
if (*p == cOld) {
*p = cNew;
}
p++;
}
return str;
}
char *strreplaceStr(char *pszBuf, const char *pszTok, const char *pszNewTok) {
// Can't access nullptr pointers
assert(pszBuf != nullptr);
assert(pszTok != nullptr);
assert(pszNewTok != nullptr);
// Search token, and new token can't be the same
assert(strcmp(pszTok, pszNewTok) != 0);
int nTok = strlen(pszTok);
int nNewTok = strlen(pszNewTok);
int nDiff = nTok - nNewTok;
char *p = pszBuf;
for (char *pszSearch = strstr(p, pszTok); pszSearch; pszSearch = strstr(p, pszTok)) {
char *pszEndTok = pszSearch + nTok;
if (nDiff != 0) {
memmove(pszEndTok - nDiff, pszEndTok, strlen(pszEndTok) + 1);
}
memcpy(pszSearch, pszNewTok, nNewTok);
}
return pszBuf;
}
void memreplaceChar(byte *pBuf, byte chOld, byte chNew, int32 lSize) {
assert(pBuf != nullptr);
assert(chOld != chNew);
while (lSize-- > 0) {
if (*pBuf == chOld) {
*pBuf = chNew;
}
pBuf++;
}
}
} // namespace Bagel

View File

@@ -0,0 +1,65 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BAGEL_BOFLIB_STRING_FUNCTIONS_H
#define BAGEL_BOFLIB_STRING_FUNCTIONS_H
namespace Bagel {
/**
* Counts number of occurrences of a specified char in String
* @param str Pointer to string to parse
* @param c Character to count in str
* @return Number of times character c occurs in string str
*/
extern int strCharCount(const char *str, char c);
/**
* Replaces all occurrences of cOld in string with cNew
* @param pszbuf String to search
* @param cOld Character to find in pszBuf
* @param cNew Character to replace cOld
* @return Pointer to pszBuf
*/
extern char *strreplaceChar(char *pszbuf, char cOld, char cNew);
/**
* Replaces every occurrence of 1 character with another
* @param pBuf Buffer to search
* @param chOld Old character to be replaced
* @param chNew New character to replace with
* @param lSize Size of buffer
*/
extern void memreplaceChar(byte *pBuf, byte chOld, byte chNew, int32 lSize);
/**
* Replaces all tokens in string with new token
* @param pszBuf Buffer to search
* @param pszTok1 Token to search for in pszBuf
* @param pszTok2 Replacement token
* @return Pointer to pszBuf.
*/
extern char *strreplaceStr(char *pszBuf, const char *pszTok1, const char *pszTok2);
} // namespace Bagel
#endif