diff options
70 files changed, 4216 insertions, 905 deletions
diff --git a/backends/midi/quicktime.cpp b/backends/midi/quicktime.cpp index 568adf022b..a18eadcb30 100644 --- a/backends/midi/quicktime.cpp +++ b/backends/midi/quicktime.cpp @@ -132,8 +132,7 @@ bail: return MERR_DEVICE_NOT_AVAILABLE; } -void MidiDriver_QT::close() -{ +void MidiDriver_QT::close() { MidiDriver_MPU401::close(); dispose(); } @@ -248,8 +247,7 @@ void MidiDriver_QT::setPitchBendRange (byte channel, uint range) { NASetController(qtNoteAllocator, qtNoteChannel[channel], kControllerPitchBend, theBend); } -void MidiDriver_QT::dispose() -{ +void MidiDriver_QT::dispose() { for (int i = 0; i < 16; i++) { if (qtNoteChannel[i] != 0) NADisposeNoteChannel(qtNoteAllocator, qtNoteChannel[i]); diff --git a/backends/platform/ps2/Makefile.ps2 b/backends/platform/ps2/Makefile.ps2 index 22cd4eaa1b..204f4f7a16 100644 --- a/backends/platform/ps2/Makefile.ps2 +++ b/backends/platform/ps2/Makefile.ps2 @@ -19,16 +19,17 @@ RM = rm -f srcdir = ../../.. VPATH = $(srcdir) INCDIR = ../../../ +DEPDIR = .deps DEFINES = -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_MPEG2 -DUSE_ZLIB -D_EE -D__PLAYSTATION2__ -O2 -Wall -Wno-multichar # PS2SDK-Ports from ps2dev.org's SVN repository for libmad, zlib and ucl -PS2SDK_PORTS = /home/robby/libStuffNew/ps2sdk-ports +PS2SDK_PORTS = /mnt/winxp/scummvm/ports PS2SDK_PORTS_INCS = /ucl /zlib/include /libmad/ee/include PS2SDK_PORTS_LIBS = /ucl /zlib/lib /libmad/ee/lib # we also need SjPcm, Tremor and libmpeg2 -MORE_LIBS_DIR = /home/robby/libStuff +MORE_LIBS_DIR = /mnt/winxp/scummvm/ports MORE_LIBS_INCS = /SjPcm/ee/src /mpeg2dec/include /tremor MORE_LIBS_LIBS = /SjPcm/ee/lib /mpeg2dec/libmpeg2 /tremor/tremor diff --git a/backends/platform/ps2/fileio.cpp b/backends/platform/ps2/fileio.cpp index bc310a43f4..b7fa8d03f1 100644 --- a/backends/platform/ps2/fileio.cpp +++ b/backends/platform/ps2/fileio.cpp @@ -340,8 +340,6 @@ FILE *ps2_fopen(const char *fname, const char *mode) { assert(cacheListSema >= 0); } - //printf("ps2_fopen: %s, %s\n", fname, mode); - if (((mode[0] != 'r') && (mode[0] != 'w')) || ((mode[1] != '\0') && (mode[1] != 'b'))) { printf("unsupported mode \"%s\" for file \"%s\"\n", mode, fname); return NULL; @@ -363,6 +361,8 @@ FILE *ps2_fopen(const char *fname, const char *mode) { } else { // Regular access to one of the devices + printf("ps2_fopen = %s\n", fname); // romeo : temp + if (!rdOnly) return NULL; // we only provide readaccess for cd,dvd,hdd,usb @@ -378,19 +378,22 @@ FILE *ps2_fopen(const char *fname, const char *mode) { } int64 cacheId = -1; - if (rdOnly && tocManager.haveEntries()) + if (tocManager.haveEntries()) cacheId = tocManager.fileExists(fname); if (cacheId != 0) { Ps2File *file = findInCache(cacheId); - if (file) + if (file) { + printf(" findInCache(%x)\n", cacheId); // romeo : temp return (FILE*)file; + } bool isAudioFile = strstr(fname, ".bun") || strstr(fname, ".BUN") || strstr(fname, ".Bun"); file = new Ps2ReadFile(cacheId, isAudioFile); if (file->open(fname)) { openFileCount++; + printf(" new cacheID = %x\n", cacheId); // romeo : temp return (FILE*)file; } else delete file; @@ -579,7 +582,7 @@ void TocManager::readEntries(const char *root) { } char readPath[256]; sprintf(readPath, "%s/", _root); - printf("readDir: %s\n", readPath); + printf("readDir: %s (root: %s )\n", readPath, root); readDir(readPath, &_rootNode, 0); } @@ -587,28 +590,62 @@ void TocManager::readDir(const char *path, TocNode **node, int level) { if (level <= 2) { // we don't scan deeper than that iox_dirent_t dirent; int fd = fio.dopen(path); + TocNode *eNode = NULL; // = *node; // entry node + bool first = true; + + printf("path=%s - level=%d fd=%d\n", path, level, fd); // romeo : temp if (fd >= 0) { - while (fio.dread(fd, &dirent) > 0) - if (dirent.name[0] != '.') { // skip '.' and '..' + while (fio.dread(fd, &dirent) > 0) { + if (dirent.name[0] != '.') { // skip '.' & '..' - romeo : check + // --- do we have them on PS2? *node = new TocNode; + if (first) { + eNode = *node; + first = false; + } (*node)->sub = (*node)->next = NULL; - (*node)->nameLen = strlen(dirent.name); memcpy((*node)->name, dirent.name, (*node)->nameLen + 1); - if (dirent.stat.mode & FIO_S_IFDIR) { // directory + if (dirent.stat.mode & FIO_S_IFDIR) { (*node)->isDir = true; - char nextPath[256]; - sprintf(nextPath, "%s%s/", path, dirent.name); - readDir(nextPath, &((*node)->sub), level + 1); - } else + printf("dirent.name = %s [DIR]\n", dirent.name); + } + else { (*node)->isDir = false; + printf("dirent.name = %s\n", dirent.name); + } + node = &((*node)->next); } + } + fio.dclose(fd); - } else - printf("Can't open path: %s\n", path); + } + + TocNode *iNode = eNode; + char nextPath[256]; + + while (iNode) { + if (iNode->isDir == true) { + sprintf(nextPath, "%s%s/", path, iNode->name); + readDir(nextPath, &(iNode->sub), level + 1); + } + iNode = iNode->next; + } + } + + /* + ** Wizard of Oz' trick (to get all games running from USB on PS2): + + 1. Make a list of files / dirs in level #0 (dclose before continuing) + + 2. Go through the dirs : dopen / dread them / mark dirs / dclose + + It's a safe recursion, cause it recurses on 'isDir' nodes + after dclosing the higher hierarchy + */ } int64 TocManager::fileExists(const char *name) { diff --git a/backends/platform/ps2/iop/rpckbd/Makefile b/backends/platform/ps2/iop/rpckbd/Makefile new file mode 100644 index 0000000000..b25efa3660 --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/Makefile @@ -0,0 +1,30 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ + + +IOP_OBJS_DIR = obj/ +IOP_BIN_DIR = bin/ +IOP_SRC_DIR = src/ +IOP_INC_DIR = include/ + +IOP_BIN=bin/rpckbd.irx +IOP_OBJS=obj/ps2kbd.o obj/imports.o + +IOP_CFLAGS=-Wall +IOP_INCS += -I$(PS2SDKSRC)/iop/usb/usbd/include + +all: $(IOP_OBJS_DIR) $(IOP_BIN_DIR) $(IOP_BIN) + +clean: + rm -f -r $(IOP_OBJS_DIR) $(IOP_BIN_DIR) + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/iop/Rules.make +include $(PS2SDKSRC)/iop/Rules.release diff --git a/backends/platform/ps2/iop/rpckbd/include/ps2kbd.h b/backends/platform/ps2/iop/rpckbd/include/ps2kbd.h new file mode 100644 index 0000000000..f16c7ca12b --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/include/ps2kbd.h @@ -0,0 +1,90 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ +# USB Keyboard Driver for PS2 +*/ + +#ifndef __PS2KBD_H__ +#define __PS2KBD_H__ + +#define PS2KBD_RPC_ID 0xb0b0b80 + +#define PS2KBD_LED_NUMLOCK 1 +#define PS2KBD_LED_CAPSLOCK 2 +#define PS2KBD_LED_SCRLOCK 4 +#define PS2KBD_LED_COMPOSE 8 +#define PS2KBD_LED_KANA 16 + +#define PS2KBD_LED_MASK 0x1F; + +#define PS2KBD_ESCAPE_KEY 0x1B + +#define PS2KBD_LEFT_CTRL (1 << 0) +#define PS2KBD_LEFT_SHIFT (1 << 1) +#define PS2KBD_LEFT_ALT (1 << 2) +#define PS2KBD_LEFT_GUI (1 << 3) +#define PS2KBD_RIGHT_CTRL (1 << 4) +#define PS2KBD_RIGHT_SHIFT (1 << 5) +#define PS2KBD_RIGHT_ALT (1 << 6) +#define PS2KBD_RIGHT_GUI (1 << 7) + +#define PS2KBD_CTRL (PS2KBD_LEFT_CTRL | PS2KBD_RIGHT_CTRL) +#define PS2KBD_SHIFT (PS2KBD_LEFT_SHIFT | PS2KBD_RIGHT_SHIFT) +#define PS2KBD_ALT (PS2KBD_LEFT_ALT | PS2KBD_RIGHT_ALT) +#define PS2KBD_GUI (PS2KBD_LEFT_GUI | PS2KBD_RIGHT_GUI) + +#define PS2KBD_RAWKEY_UP 0xF0 +#define PS2KBD_RAWKEY_DOWN 0xF1 + +typedef struct _kbd_rawkey { + u8 state; + u8 key; +} kbd_rawkey __attribute__ ((packed)); + +#define PS2KBD_READMODE_NORMAL 1 +#define PS2KBD_READMODE_RAW 2 + +/* Notes on read mode */ +/* In normal readmode (default) read multiples of 1 character off the keyboard file. These are + processed by the keymaps so that you get back ASCII data */ +/* In raw readmode must read multiples of 2. First byte indicates state (i.e. Up or Down) + Second byte is the USB key code for that key. This table is presented in the USB HID Usage Tables manaual + from usb.org */ + +#define PS2KBD_KEYMAP_SIZE 256 + +typedef struct _kbd_keymap + +{ + u8 keymap[PS2KBD_KEYMAP_SIZE]; + u8 shiftkeymap[PS2KBD_KEYMAP_SIZE]; + u8 keycap[PS2KBD_KEYMAP_SIZE]; +} kbd_keymap; + + +/* IRPC function numbers */ +#define KBD_RPC_SETREADMODE 1 /* Sets up keymapped or raw mode */ +#define KBD_RPC_SETLEDS 2 /* Sets the LED state for ALL keyboards connected */ +#define KBD_RPC_SETREPEATRATE 3 /* Sets the repeat rate of the keyboard */ +#define KBD_RPC_SETKEYMAP 4 /* Sets the keymap for the standard keys, non shifted and shifted */ +#define KBD_RPC_SETCTRLMAP 5 /* Sets the control key mapping */ +#define KBD_RPC_SETALTMAP 6 /* Sets the alt key mapping */ +#define KBD_RPC_SETSPECIALMAP 7 /* Sets the special key mapping */ +#define KBD_RPC_FLUSHBUFFER 9 /* Flush the internal buffer, probably best after a keymap change */ +#define KBD_RPC_RESETKEYMAP 10 /* Reset keymaps to default states */ +#define KBD_RPC_READKEY 11 +#define KBD_RPC_READRAW 12 + +/* Note on keymaps. In normal keymap a 0 would indicate no key */ +/* Key maps are represented by 3 256*8bit tables. First table maps USB key to a char when not shifted */ +/* Second table maps USB key to a char when shifted */ +/* Third table contains boolean values. If 1 then the key is shifted/unshifted in capslock, else capslock is ignored */ + +#endif diff --git a/backends/platform/ps2/iop/rpckbd/src/imports.lst b/backends/platform/ps2/iop/rpckbd/src/imports.lst new file mode 100644 index 0000000000..41e13e6e73 --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/src/imports.lst @@ -0,0 +1,58 @@ + +sysclib_IMPORTS_start +I_memset +I_strcmp +I_memcpy +sysclib_IMPORTS_end + +loadcore_IMPORTS_start +I_FlushDcache +loadcore_IMPORTS_end + +sifcmd_IMPORTS_start +I_sceSifInitRpc +I_sceSifSetRpcQueue +I_sceSifRegisterRpc +I_sceSifRpcLoop +sifcmd_IMPORTS_end + +stdio_IMPORTS_start +I_printf +stdio_IMPORTS_end + +thsemap_IMPORTS_start +I_CreateSema +I_SignalSema +I_WaitSema +I_PollSema +I_DeleteSema +thsemap_IMPORTS_end + +thbase_IMPORTS_start +I_StartThread +I_CreateThread +I_USec2SysClock +I_iSetAlarm +I_SetAlarm +I_CancelAlarm +thbase_IMPORTS_end + +thevent_IMPORTS_start +I_WaitEventFlag +I_iSetEventFlag +I_CreateEventFlag +thevent_IMPORTS_end + +sysmem_IMPORTS_start +I_AllocSysMemory +I_FreeSysMemory +sysmem_IMPORTS_end + +usbd_IMPORTS_start +I_UsbGetDeviceStaticDescriptor +I_UsbOpenEndpoint +I_UsbSetDevicePrivateData +I_UsbTransfer +I_UsbRegisterDriver +usbd_IMPORTS_end + diff --git a/backends/platform/ps2/iop/rpckbd/src/irx_imports.h b/backends/platform/ps2/iop/rpckbd/src/irx_imports.h new file mode 100644 index 0000000000..6ecc8e5864 --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/src/irx_imports.h @@ -0,0 +1,35 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org> +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ +# Defines all IRX imports. +*/ + +#ifndef IOP_IRX_IMPORTS_H +#define IOP_IRX_IMPORTS_H + +#include "irx.h" + +/* Please keep these in alphabetical order! */ +#include "dmacman.h" +#include "intrman.h" +#include "libsd.h" +#include "loadcore.h" +#include "sifcmd.h" +#include "stdio.h" +#include "sysclib.h" +#include "sysmem.h" +#include "thbase.h" +#include "thevent.h" +#include "thmsgbx.h" +#include "thsemap.h" +#include "usbd.h" +#include "vblank.h" + +#endif /* IOP_IRX_IMPORTS_H */ diff --git a/backends/platform/ps2/iop/rpckbd/src/ps2kbd.c b/backends/platform/ps2/iop/rpckbd/src/ps2kbd.c new file mode 100644 index 0000000000..f87a47f0cb --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/src/ps2kbd.c @@ -0,0 +1,1199 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2005, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ +# USB Keyboard Driver for PS2 +*/ + +#include "types.h" +#include "ioman.h" +#include "loadcore.h" +#include "stdio.h" +#include "sifcmd.h" +#include "sifrpc.h" +#include "sysclib.h" +#include "sysmem.h" +#include "usbd.h" +#include "usbd_macro.h" +#include "thbase.h" +#include "thevent.h" +#include "thsemap.h" + +#include "ps2kbd.h" +#include "us_keymap.h" + +#define PS2KBD_VERSION 0x100 + +#define USB_SUBCLASS_BOOT 1 +#define USB_HIDPROTO_KEYBOARD 1 + +#define PS2KBD_MAXDEV 2 +#define PS2KBD_MAXKEYS 6 + +#define PS2KBD_DEFLINELEN 4096 +#define PS2KBD_DEFREPEATRATE 100 +/* Default repeat rate in milliseconds */ +#define PS2KBD_REPEATWAIT 1000 +/* Number of milliseconds to wait before starting key repeat */ +#define USB_KEYB_NUMLOCK 0x53 +#define USB_KEYB_CAPSLOCK 0x39 +#define USB_KEYB_SCRLOCK 0x47 + +#define USB_KEYB_NUMPAD_START 0x54 +#define USB_KEYB_NUMPAD_END 0x63 + +#define SEMA_ZERO -419 +#define SEMA_DELETED -425 + +int ps2kbd_init(); +void ps2kbd_config_set(int resultCode, int bytes, void *arg); +void ps2kbd_idlemode_set(int resultCode, int bytes, void *arg); +void ps2kbd_data_recv(int resultCode, int bytes, void *arg); +int ps2kbd_probe(int devId); +int ps2kbd_connect(int devId); +int ps2kbd_disconnect(int devId); +void usb_getstring(int endp, int index, char *desc); + +typedef struct _kbd_data_recv + +{ + u8 mod_keys; + u8 reserved; + u8 keycodes[PS2KBD_MAXKEYS]; +} kbd_data_recv; + +typedef struct _keyb_dev + +{ + int configEndp; + int dataEndp; + int packetSize; + int devId; + int interfaceNo; /* Holds the interface number selected on this device */ + char repeatkeys[2]; + u32 eventmask; + u8 ledStatus; /* Maintains state on the led status */ + kbd_data_recv oldData; + kbd_data_recv data; /* Holds the data for the transfers */ +} kbd_dev; + +/* Global Variables */ + +int kbd_readmode; +u32 kbd_repeatrate; +kbd_dev *devices[PS2KBD_MAXDEV]; /* Holds a list of current devices */ +int dev_count; +UsbDriver kbd_driver = { NULL, NULL, "PS2Kbd", ps2kbd_probe, ps2kbd_connect, ps2kbd_disconnect }; +u8 *lineBuffer; +u32 lineStartP, lineEndP; +int lineSema; +int bufferSema; +u32 lineSize; +u8 keymap[PS2KBD_KEYMAP_SIZE]; /* Normal key map */ +u8 shiftkeymap[PS2KBD_KEYMAP_SIZE]; /* Shifted key map */ +u8 keycap[PS2KBD_KEYMAP_SIZE]; /* Does this key get shifted by capslock ? */ +u8 special_keys[PS2KBD_KEYMAP_SIZE]; +u8 control_map[PS2KBD_KEYMAP_SIZE]; +u8 alt_map[PS2KBD_KEYMAP_SIZE]; +//static struct fileio_driver kbd_fdriver; +iop_device_t kbd_filedrv; +u8 keyModValue[8] = { 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7 }; +int repeat_tid; +int eventid; /* Id of the repeat event */ + +int _start () +{ + FlushDcache(); + + ps2kbd_init(); + + printf("PS2KBD - USB Keyboard Library\n"); + + return 0; + +} + +int ps2kbd_probe(int devId) + +{ + UsbDeviceDescriptor *dev; + UsbConfigDescriptor *conf; + UsbInterfaceDescriptor *intf; + UsbEndpointDescriptor *endp; + //UsbStringDescriptor *str; + + if(dev_count >= PS2KBD_MAXDEV) + { + printf("ERROR: Maximum keyboard devices reached\n"); + return 0; + } + + //printf("PS2Kbd_probe devId %d\n", devId); + + dev = UsbGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE); /* Get device descriptor */ + if(!dev) + { + printf("ERROR: Couldn't get device descriptor\n"); + return 0; + } + + //printf("Device class %d, Size %d, Man %d, Product %d Cpnfigurations %d\n", dev->bDeviceClass, dev->bMaxPacketSize0, dev->iManufacturer, dev->iProduct, dev->bNumConfigurations); + /* Check that the device class is specified in the interfaces and it has at least one configuration */ + if((dev->bDeviceClass != USB_CLASS_PER_INTERFACE) || (dev->bNumConfigurations < 1)) + { + //printf("This is not the droid you're looking for\n"); + return 0; + } + + conf = UsbGetDeviceStaticDescriptor(devId, dev, USB_DT_CONFIG); + if(!conf) + { + printf("ERROR: Couldn't get configuration descriptor\n"); + return 0; + } + //printf("Config Length %d Total %d Interfaces %d\n", conf->bLength, conf->wTotalLength, conf->bNumInterfaces); + + if((conf->bNumInterfaces < 1) || (conf->wTotalLength < (sizeof(UsbConfigDescriptor) + sizeof(UsbInterfaceDescriptor)))) + { + printf("ERROR: No interfaces available\n"); + return 0; + } + + intf = (UsbInterfaceDescriptor *) ((char *) conf + conf->bLength); /* Get first interface */ +/* printf("Interface Length %d Endpoints %d Class %d Sub %d Proto %d\n", intf->bLength, */ +/* intf->bNumEndpoints, intf->bInterfaceClass, intf->bInterfaceSubClass, */ +/* intf->bInterfaceProtocol); */ + + if((intf->bInterfaceClass != USB_CLASS_HID) || (intf->bInterfaceSubClass != USB_SUBCLASS_BOOT) || + (intf->bInterfaceProtocol != USB_HIDPROTO_KEYBOARD) || (intf->bNumEndpoints < 1)) + + { + //printf("We came, we saw, we told it to fuck off\n"); + return 0; + } + + endp = (UsbEndpointDescriptor *) ((char *) intf + intf->bLength); + endp = (UsbEndpointDescriptor *) ((char *) endp + endp->bLength); /* Go to the data endpoint */ + + //printf("Endpoint 1 Addr %d, Attr %d, MaxPacket %d\n", endp->bEndpointAddress, endp->bmAttributes, endp->wMaxPacketSizeLB); + + if(((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) || + ((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)) + { + printf("ERROR: Endpoint not interrupt type and/or an input\n"); + return 0; + } + + printf("PS2KBD: Found a keyboard device\n"); + + return 1; +} + +int ps2kbd_connect(int devId) + +{ + /* Assume we can only get here if we have already checked the device is kosher */ + + UsbDeviceDescriptor *dev; + UsbConfigDescriptor *conf; + UsbInterfaceDescriptor *intf; + UsbEndpointDescriptor *endp; + kbd_dev *currDev; + int devLoop; + + //printf("PS2Kbd_connect devId %d\n", devId); + + dev = UsbGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE); /* Get device descriptor */ + if(!dev) + { + printf("ERROR: Couldn't get device descriptor\n"); + return 1; + } + + conf = UsbGetDeviceStaticDescriptor(devId, dev, USB_DT_CONFIG); + if(!conf) + { + printf("ERROR: Couldn't get configuration descriptor\n"); + return 1; + } + + intf = (UsbInterfaceDescriptor *) ((char *) conf + conf->bLength); /* Get first interface */ + endp = (UsbEndpointDescriptor *) ((char *) intf + intf->bLength); + endp = (UsbEndpointDescriptor *) ((char *) endp + endp->bLength); /* Go to the data endpoint */ + + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + if(devices[devLoop] == NULL) + { + break; + } + } + + if(devLoop == PS2KBD_MAXDEV) + { + /* How the f*** did we end up here ??? */ + printf("ERROR: Device Weirdness!!\n"); + return 1; + } + + currDev = (kbd_dev *) AllocSysMemory(0, sizeof(kbd_dev), NULL); + if(!currDev) + { + printf("ERROR: Couldn't allocate a device point for the kbd\n"); + return 1; + } + + devices[devLoop] = currDev; + memset(currDev, 0, sizeof(kbd_dev)); + currDev->configEndp = UsbOpenEndpoint(devId, NULL); + currDev->dataEndp = UsbOpenEndpoint(devId, endp); + currDev->packetSize = endp->wMaxPacketSizeLB | ((int) endp->wMaxPacketSizeHB << 8); + currDev->eventmask = (1 << devLoop); + if(currDev->packetSize > sizeof(kbd_data_recv)) + { + currDev->packetSize = sizeof(kbd_data_recv); + } + + if(dev->iManufacturer != 0) + { + usb_getstring(currDev->configEndp, dev->iManufacturer, "Keyboard Manufacturer"); + } + + if(dev->iProduct != 0) + { + usb_getstring(currDev->configEndp, dev->iProduct, "Keyboard Product"); + } + + currDev->devId = devId; + currDev->interfaceNo = intf->bInterfaceNumber; + currDev->ledStatus = 0; + + UsbSetDevicePrivateData(devId, currDev); /* Set the index for the device data */ + + //printf("Configuration value %d\n", conf->bConfigurationValue); + UsbSetDeviceConfiguration(currDev->configEndp, conf->bConfigurationValue, ps2kbd_config_set, currDev); + + dev_count++; /* Increment device count */ + printf("PS2KBD: Connected device\n"); + + return 0; +} + +int ps2kbd_disconnect(int devId) + +{ + int devLoop; + printf("PS2Kbd_disconnect devId %d\n", devId); + + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + if((devices[devLoop]) && (devices[devLoop]->devId == devId)) + { + dev_count--; + FreeSysMemory(devices[devLoop]); + devices[devLoop] = NULL; + printf("PS2KBD: Disconnected device\n"); + break; + } + } + + return 0; +} + +typedef struct _string_descriptor + +{ + u8 buf[200]; + char *desc; +} string_descriptor; + +void ps2kbd_getstring_set(int resultCode, int bytes, void *arg) + +{ + UsbStringDescriptor *str = (UsbStringDescriptor *) arg; + string_descriptor *strBuf = (string_descriptor *) arg; + char string[50]; + int strLoop; + +/* printf("=========getstring=========\n"); */ + +/* printf("PS2KEYBOARD: GET_DESCRIPTOR res %d, bytes %d, arg %p\n", resultCode, bytes, arg); */ + + if(resultCode == USB_RC_OK) + { + memset(string, 0, 50); + for(strLoop = 0; strLoop < ((bytes - 2) / 2); strLoop++) + { + string[strLoop] = str->wData[strLoop] & 0xFF; + } + printf("%s: %s\n", strBuf->desc, string); + } + + FreeSysMemory(arg); +} + +void usb_getstring(int endp, int index, char *desc) + +{ + u8 *data; + string_descriptor *str; + int ret; + + data = (u8 *) AllocSysMemory(0, sizeof(string_descriptor), NULL); + str = (string_descriptor *) data; + + if(data != NULL) + { + str->desc = desc; + ret = UsbControlTransfer(endp, 0x80, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | index, + 0, sizeof(string_descriptor) - 4, data, ps2kbd_getstring_set, data); + if(ret != USB_RC_OK) + { + printf("PS2KBD: Error sending string descriptor request\n"); + FreeSysMemory(data); + } + } +} + +void ps2kbd_config_set(int resultCode, int bytes, void *arg) + /* Called when we have finished choosing our configuration */ + +{ + kbd_dev *dev; + + if(resultCode != USB_RC_OK) + { + printf("PS2KEYBOARD: Configuration set error res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + return; + } + + //printf("PS2KEYBOARD: Configuration set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + /* Do a interrupt data transfer */ + + dev = (kbd_dev *) arg; + if(dev != NULL) + { + int ret; + + ret = UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_IDLE, 0, dev->interfaceNo, 0, NULL, ps2kbd_idlemode_set, arg); + } +} + +void ps2kbd_idlemode_set(int resultCode, int bytes, void *arg) + +{ + kbd_dev *dev; + + + + if(resultCode != USB_RC_OK) + { + printf("PS2KBD: Idlemode set error res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + return; + } + + dev = (kbd_dev *) arg; + if(dev != NULL) + { + int ret; + + ret = UsbInterruptTransfer(dev->dataEndp, &dev->data, dev->packetSize, ps2kbd_data_recv, arg); + } +} + +void ps2kbd_led_set(int resultCode, int bytes, void *arg) + +{ + //printf("LED Set\n"); +} + +void ps2kbd_build_uniquekeys(u8 *res, const u8 *new, const u8 *old) + + /* Builds a list of unique keys */ + +{ + int loopNew, loopOld; + int loopRes = 0; + int foundKey; + + for(loopNew = 0; loopNew < PS2KBD_MAXKEYS; loopNew++) + { + if(new[loopNew] != 0) + { + foundKey = 0; + for(loopOld = 0; loopOld < PS2KBD_MAXKEYS; loopOld++) + { + if(new[loopNew] == old[loopOld]) + { + foundKey = 1; + break; + } + } + if(!foundKey) + { + res[loopRes++] = new[loopNew]; + } + } + } +} + +u32 ps2kbd_repeathandler(void *arg) + +{ + kbd_dev *dev = arg; + iop_sys_clock_t t; + //printf("Repeat handler\n"); + + iSetEventFlag(eventid, dev->eventmask); + + USec2SysClock(kbd_repeatrate * 1000, &t); + iSetAlarm(&t, ps2kbd_repeathandler, arg); + + return t.hi; +} + +void ps2kbd_getkeys(u8 keyMods, u8 ledStatus, const u8 *keys, kbd_dev *dev) + +{ + int loopKey; + int tempPos = 0; + int byteCount = 0; + u8 currChars[2]; + + if(lineStartP < lineEndP) + { + tempPos = lineStartP + lineSize; + } + else + { + tempPos = lineStartP; + } + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) + { + u8 currKey = keys[loopKey]; + + currChars[0] = 0; + currChars[1] = 0; + + if(lineEndP == (tempPos - 1)) + { + break; + } + + if(currKey) /* If this is a valid key */ + { + if((currKey >= USB_KEYB_NUMPAD_START) && (currKey <= USB_KEYB_NUMPAD_END)) + /* Handle numpad specially */ + { + if(ledStatus & PS2KBD_LED_NUMLOCK) + { + if(keymap[currKey]) + { + currChars[0] = keymap[currKey]; + } + } + else + { + if(special_keys[currKey]) + { + currChars[0] = PS2KBD_ESCAPE_KEY; + currChars[1] = special_keys[currKey]; + } + else if(keymap[currKey] != '5') /* Make sure this isnt a 5 key :) */ + { + currChars[0] = keymap[currKey]; + } + } + } + else if(special_keys[currKey]) /* This is a special key */ + { + currChars[0] = PS2KBD_ESCAPE_KEY; + currChars[1] = special_keys[currKey]; + } + else if(keyMods & PS2KBD_CTRL) /* CTRL */ + { + if(control_map[currKey]) + { + currChars[0] = control_map[currKey]; + } + } + else if(keyMods & PS2KBD_ALT) /* ALT */ + { + if(alt_map[currKey]) + { + currChars[0] = alt_map[currKey]; + } + } + else if(keyMods & PS2KBD_SHIFT) /* SHIFT */ + { + if((ledStatus & PS2KBD_LED_CAPSLOCK) && (keycap[currKey])) + { + currChars[0] = keymap[currKey]; + } + else + { + currChars[0] = shiftkeymap[currKey]; + } + } + else /* Normal key */ + { + if(keymap[keys[loopKey]]) + { + if((ledStatus & PS2KBD_LED_CAPSLOCK) && (keycap[currKey])) + { + currChars[0] = shiftkeymap[currKey]; + } + else + { + currChars[0] = keymap[currKey]; + } + } + } + } + + if((currChars[0] == PS2KBD_ESCAPE_KEY) && (currChars[1] != 0)) + { + if(lineEndP != (tempPos - 2)) + { + lineBuffer[lineEndP++] = currChars[0]; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = currChars[1]; + lineEndP %= lineSize; + byteCount += 2; + } + dev->repeatkeys[0] = currChars[0]; + dev->repeatkeys[1] = currChars[1]; + } + else if(currChars[0] != 0) + { + lineBuffer[lineEndP++] = currChars[0]; + lineEndP %= lineSize; + byteCount++; + dev->repeatkeys[0] = currChars[0]; + dev->repeatkeys[1] = 0; + } + } + + if(byteCount > 0) + { + iop_sys_clock_t t; + /* Set alarm to do repeat rate */ + //printf("repeatkeys %d %d\n", kbd_repeatkeys[0], kbd_repeatkeys[1]); + USec2SysClock(PS2KBD_REPEATWAIT * 1000, &t); + SetAlarm(&t, ps2kbd_repeathandler, dev); + } + + for(loopKey = 0; loopKey < byteCount; loopKey++) /* Signal the sema to indicate data */ + { + SignalSema(bufferSema); + } + +/* lineBuffer[PS2KBD_DEFLINELEN - 1] = 0; */ +/* printf(lineBuffer); */ + //printf("lineStart %d, lineEnd %d\n", lineStartP, lineEndP); +} + + +void ps2kbd_getkeys_raw(u8 newKeyMods, u8 oldKeyMods, u8 *new, const u8 *old) + +{ + int loopKey; + u8 currKey; + u8 keyMods = newKeyMods ^ oldKeyMods; + u8 keyModsMap = newKeyMods & keyMods; + int tempPos = 0; + int byteCount = 0; + + if(lineStartP < lineEndP) + { + tempPos = lineStartP + lineSize; + } + else + { + tempPos = lineStartP; + } + + for(loopKey = 0; loopKey < 8; loopKey++) + { + int currMod = (1 << loopKey); + if(keyMods & currMod) + { + if(lineEndP == (tempPos - 2)) + { + return; + } + + currKey = keyModValue[loopKey]; + + if(keyModsMap & currMod) /* If key pressed */ + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_DOWN; + //printf("Key down\n"); + } + else + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_UP; + //printf("Key up\n"); + } + + lineEndP %= lineSize; + lineBuffer[lineEndP++] = currKey; + lineEndP %= lineSize; + byteCount += 2; + //printf("Key %d\n", currKey); + } + } + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) + { + if(lineEndP == (tempPos - 2)) + { + return; + } + + if(new[loopKey] != 0) + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_DOWN; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = new[loopKey]; + lineEndP %= lineSize; + byteCount += 2; + //printf("Key down\nKey %d\n", new[loopKey]); + } + + } + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) + { + if(lineEndP == (tempPos - 2)) + { + return; + } + + if(old[loopKey] != 0) + { + lineBuffer[lineEndP++] = PS2KBD_RAWKEY_UP; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = old[loopKey]; + lineEndP %= lineSize; + byteCount += 2; + //printf("Key up\nKey %d\n", old[loopKey]); + } + + } + + for(loopKey = 0; loopKey < byteCount; loopKey++) /* Signal the sema for the number of bytes read */ + { + SignalSema(bufferSema); + } +} + +void ps2kbd_data_recv(int resultCode, int bytes, void *arg) + +{ + kbd_dev *dev; + int ret; + int phantom; + int loop; + + if(resultCode != USB_RC_OK) + { + printf("PS2KEYBOARD: Data Recv set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + return; + } + + //printf("PS2KBD: Data Recv set res %d, bytes %d, arg %p\n", resultCode, bytes, arg); + + dev = (kbd_dev *) arg; + if(dev == NULL) + { + printf("PS2KBD: dev == NULL\n"); + return; + } + +/* printf("PS2KBD Modifiers %02X, Keys ", dev->data.mod_keys); */ +/* for(loop = 0; loop < PS2KBD_MAXKEYS; loop++) */ +/* { */ +/* printf("%02X ", dev->data.keycodes[loop]); */ +/* } */ +/* printf("\n"); */ + + CancelAlarm(ps2kbd_repeathandler, dev); /* Make sure repeat alarm is cancelled */ + + /* Check for phantom states */ + phantom = 1; + for(loop = 0; loop < PS2KBD_MAXKEYS; loop++) + { + if(dev->data.keycodes[loop] != 1) + { + phantom = 0; + break; + } + } + + if(!phantom) /* If not in a phantom state */ + { + u8 uniqueKeys[PS2KBD_MAXKEYS]; + u8 missingKeys[PS2KBD_MAXKEYS]; + int loopKey; + + memset(uniqueKeys, 0, PS2KBD_MAXKEYS); + memset(missingKeys, 0, PS2KBD_MAXKEYS); + ps2kbd_build_uniquekeys(uniqueKeys, dev->data.keycodes, dev->oldData.keycodes); + ps2kbd_build_uniquekeys(missingKeys, dev->oldData.keycodes, dev->data.keycodes); + /* Build new and missing key lists */ + +/* printf("Unique keys : "); */ +/* for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) */ +/* { */ +/* printf("%02X ", uniqueKeys[loopKey]); */ +/* } */ +/* printf("\n"); */ + +/* printf("Missing keys : "); */ +/* for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) */ +/* { */ +/* printf("%02X ", missingKeys[loopKey]); */ +/* } */ +/* printf("\n"); */ + + if(kbd_readmode == PS2KBD_READMODE_NORMAL) + { + u8 ledStatus; + + ledStatus = dev->ledStatus; + //printf("ledStatus %02X\n", ledStatus); + + for(loopKey = 0; loopKey < PS2KBD_MAXKEYS; loopKey++) /* Process key codes */ + { + switch(uniqueKeys[loopKey]) + { + case USB_KEYB_NUMLOCK : + ledStatus ^= PS2KBD_LED_NUMLOCK; + uniqueKeys[loopKey] = 0; + break; + case USB_KEYB_CAPSLOCK : + ledStatus ^= PS2KBD_LED_CAPSLOCK; + uniqueKeys[loopKey] = 0; + break; + case USB_KEYB_SCRLOCK : + ledStatus ^= PS2KBD_LED_SCRLOCK; + uniqueKeys[loopKey] = 0; + break; + } + } + + if(ledStatus != dev->ledStatus) + { + dev->ledStatus = ledStatus & PS2KBD_LED_MASK; + //printf("LEDS %02X\n", dev->ledStatus); + /* Call Set LEDS */ + UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_REPORT, 0x200, + dev->interfaceNo, 1, &dev->ledStatus, ps2kbd_led_set, arg); + } + + WaitSema(lineSema); /* Make sure no other thread is going to manipulate the buffer */ + ps2kbd_getkeys(dev->data.mod_keys, dev->ledStatus, uniqueKeys, dev); /* read in remaining keys */ + SignalSema(lineSema); + } + else /* RAW Mode */ + { + WaitSema(lineSema); + ps2kbd_getkeys_raw(dev->data.mod_keys, dev->oldData.mod_keys, uniqueKeys, missingKeys); + SignalSema(lineSema); + } + + memcpy(&dev->oldData, &dev->data, sizeof(kbd_data_recv)); + } + + ret = UsbInterruptTransfer(dev->dataEndp, &dev->data, dev->packetSize, ps2kbd_data_recv, arg); +} + +void flushbuffer() + +{ + iop_sema_t s; + + lineStartP = 0; + lineEndP = 0; + memset(lineBuffer, 0, lineSize); + + DeleteSema(bufferSema); + s.initial = 0; + s.max = lineSize; + s.option = 0; + s.attr = 0; + bufferSema = CreateSema(&s); /* Create a sema to maintain status of readable data */ + + if(bufferSema <= 0) + { + printf("Error creating buffer sema\n"); + } +} + +void ps2kbd_rpc_setreadmode(u32 readmode) + +{ + int devLoop; + + if(readmode == kbd_readmode) return; + + if((readmode == PS2KBD_READMODE_NORMAL) || (readmode == PS2KBD_READMODE_RAW)) + { + /* Reset line buffer */ + //printf("ioctl_setreadmode %d\n", readmode); + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + CancelAlarm(ps2kbd_repeathandler, devices[devLoop]); + } + + WaitSema(lineSema); + kbd_readmode = readmode; + flushbuffer(); + SignalSema(lineSema); + } +} + +void ps2kbd_rpc_setkeymap(kbd_keymap *keymaps) + +{ + //printf("ioctl_setkeymap %p\n", keymaps); + WaitSema(lineSema); /* Lock the input so you dont end up with weird results */ + memcpy(keymap, keymaps->keymap, PS2KBD_KEYMAP_SIZE); + memcpy(shiftkeymap, keymaps->shiftkeymap, PS2KBD_KEYMAP_SIZE); + memcpy(keycap, keymaps->keycap, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_rpc_setctrlmap(u8 *ctrlmap) + +{ + //printf("ioctl_setctrlmap %p\n", ctrlmap); + WaitSema(lineSema); + memcpy(control_map, ctrlmap, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_rpc_setaltmap(u8 *altmap) + +{ + //printf("ioctl_setaltmap %p\n", altmap); + WaitSema(lineSema); + memcpy(alt_map, altmap, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_rpc_setspecialmap(u8 *special) + +{ + //printf("ioctl_setspecialmap %p\n", special); + WaitSema(lineSema); + memcpy(special_keys, special, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_rpc_resetkeymap() + /* Reset keymap to default US variety */ + +{ + //printf("ioctl_resetkeymap()\n"); + WaitSema(lineSema); + memcpy(keymap, us_keymap, PS2KBD_KEYMAP_SIZE); + memcpy(shiftkeymap, us_shiftkeymap, PS2KBD_KEYMAP_SIZE); + memcpy(keycap, us_keycap, PS2KBD_KEYMAP_SIZE); + memcpy(special_keys, us_special_keys, PS2KBD_KEYMAP_SIZE); + memcpy(control_map, us_control_map, PS2KBD_KEYMAP_SIZE); + memcpy(alt_map, us_alt_map, PS2KBD_KEYMAP_SIZE); + SignalSema(lineSema); +} + +void ps2kbd_rpc_flushbuffer() + /* Flush the internal buffer */ + +{ + //printf("ioctl_flushbuffer()\n"); + WaitSema(lineSema); + flushbuffer(); + SignalSema(lineSema); +} + +void ps2kbd_rpc_setleds(u8 ledStatus) + +{ + int devLoop; + kbd_dev *dev; + + //printf("ioctl_setleds %d\n", ledStatus); + ledStatus &= PS2KBD_LED_MASK; + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + dev = devices[devLoop]; + if(dev) + { + if(ledStatus != dev->ledStatus) + { + dev->ledStatus = ledStatus & PS2KBD_LED_MASK; + UsbControlTransfer(dev->configEndp, 0x21, USB_REQ_SET_REPORT, 0x200, + dev->interfaceNo, 1, &dev->ledStatus, ps2kbd_led_set, dev); + } + } + } +} + +void ps2kbd_rpc_setrepeatrate(u32 rate) +{ + kbd_repeatrate = rate; +} + +int kbd_read(void *buf, int size) +{ + int count = 0; + char *data = (char *) buf; + + if(kbd_readmode == PS2KBD_READMODE_RAW) + size &= ~1; /* Ensure size of a multiple of 2 */ + + if (PollSema(bufferSema) >= 0) { + SignalSema(bufferSema); + if (WaitSema(lineSema) >= 0) { + while((count < size) && (lineStartP != lineEndP)) { + data[count] = lineBuffer[lineStartP++]; + lineStartP %= lineSize; + count++; + PollSema(bufferSema); /* Take off one count from the sema */ + } + SignalSema(lineSema); + } + } + return count; +} + +void repeat_thread(void *arg) + +{ + u32 eventmask; + int devLoop; + + for(;;) + { + WaitEventFlag(eventid, 0xFFFFFFFF, 0x01 | 0x10, &eventmask); + //printf("Recieved event %08X\n", eventmask); + for(devLoop = 0; devLoop < PS2KBD_MAXDEV; devLoop++) + { + if((eventmask & (1 << devLoop)) && (devices[devLoop])) + { + int tempPos = 0; + + WaitSema(lineSema); + if(lineStartP < lineEndP) + { + tempPos = lineStartP + lineSize; + } + else + { + tempPos = lineStartP; + } + + if((devices[devLoop]->repeatkeys[0]) && (devices[devLoop]->repeatkeys[1])) + { + if(lineEndP != (tempPos - 2)) + { + lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[0]; + lineEndP %= lineSize; + lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[1]; + lineEndP %= lineSize; + SignalSema(bufferSema); + SignalSema(bufferSema); + } + } + else if(devices[devLoop]->repeatkeys[0]) + { + if(lineEndP != (tempPos - 1)) + { + lineBuffer[lineEndP++] = devices[devLoop]->repeatkeys[0]; + lineEndP %= lineSize; + SignalSema(bufferSema); + } + } + + SignalSema(lineSema); + } + } + } +} + +int init_repeatthread() + /* Creates a thread to handle key repeats */ +{ + iop_thread_t param; + iop_event_t event; + + event.attr = 0; + event.option = 0; + event.bits = 0; + eventid = CreateEventFlag(&event); + + param.attr = TH_C; + param.thread = repeat_thread; + param.priority = 40; + param.stacksize = 0x800; + param.option = 0; + + repeat_tid = CreateThread(¶m); + if (repeat_tid > 0) { + StartThread(repeat_tid, 0); + return 0; + } + else + { + return 1; + } +} + +static unsigned long retKey; + +void *ps2kbd_rpc_server(int fno, void *data, int size) { + retKey = 0; + switch (fno) { + case KBD_RPC_SETREADMODE: + ps2kbd_rpc_setreadmode(*(u32 *)data); + break; + case KBD_RPC_SETKEYMAP: + ps2kbd_rpc_setkeymap((kbd_keymap *) data); + break; + case KBD_RPC_SETALTMAP: + ps2kbd_rpc_setaltmap((u8 *) data); + break; + case KBD_RPC_SETCTRLMAP: + ps2kbd_rpc_setctrlmap((u8 *) data); + break; + case KBD_RPC_SETSPECIALMAP: + ps2kbd_rpc_setspecialmap((u8 *) data); + break; + case KBD_RPC_FLUSHBUFFER: + ps2kbd_rpc_flushbuffer(); + break; + case KBD_RPC_SETLEDS: + ps2kbd_rpc_setleds(*(u8*) data); + break; + case KBD_RPC_RESETKEYMAP: + ps2kbd_rpc_resetkeymap(); + break; + case KBD_RPC_SETREPEATRATE: + ps2kbd_rpc_setrepeatrate(*(u32 *) data); + break; + case KBD_RPC_READRAW: + kbd_read(&retKey, 2); + return &retKey; + case KBD_RPC_READKEY: + kbd_read(&retKey, 1); + return &retKey; + default: + printf("Ps2Kbd: Unknown RPC command %d\n", fno); + break; + } + return NULL; +} + +struct t_SifRpcDataQueue qd; +struct t_SifRpcServerData sd0; +void *rpcRcvBuf; + +void ps2kbd_start_rpc(unsigned long tid) { + rpcRcvBuf = AllocSysMemory(0, 3 * PS2KBD_KEYMAP_SIZE, NULL); + printf("Ps2Kbd: starting RPC server\n"); + SifInitRpc(0); + + SifSetRpcQueue(&qd, tid); + SifRegisterRpc(&sd0, PS2KBD_RPC_ID, ps2kbd_rpc_server, rpcRcvBuf, 0, 0, &qd); + SifRpcLoop(&qd); +} + +int ps2kbd_init_rpc(void) { + struct _iop_thread param; + int th; + + param.attr = 0x02000000; + param.thread = (void*)ps2kbd_start_rpc; + param.priority = 40; + param.stacksize = 0x800; + param.option = 0; + + th = CreateThread(¶m); + + if (th > 0) { + StartThread(th, (void *)th); + return 0; + } else + return -1; +} + +int ps2kbd_init() { + int ret; + iop_sema_t s; + + s.initial = 1; + s.max = 1; + s.option = 0; + s.attr = 0; + lineSema = CreateSema(&s); + if(lineSema <= 0) + { + printf("Error creating sema\n"); + return 1; + } + + s.initial = 0; + s.max = PS2KBD_DEFLINELEN; + s.option = 0; + s.attr = 0; + bufferSema = CreateSema(&s); /* Create a sema to maintain status of readable data */ + if(bufferSema <= 0) + { + printf("Error creating buffer sema\n"); + return 1; + } + + lineBuffer = (u8 *) AllocSysMemory(0, PS2KBD_DEFLINELEN, NULL); + if(lineBuffer == NULL) + { + printf("Error allocating line buffer\n"); + return 1; + } + lineStartP = 0; + lineEndP = 0; + lineSize = PS2KBD_DEFLINELEN; + memset(lineBuffer, 0, PS2KBD_DEFLINELEN); + + memset(devices, 0, sizeof(kbd_dev *) * PS2KBD_MAXDEV); + dev_count = 0; + kbd_readmode = PS2KBD_READMODE_NORMAL; + kbd_repeatrate = PS2KBD_DEFREPEATRATE; + memcpy(keymap, us_keymap, PS2KBD_KEYMAP_SIZE); + memcpy(shiftkeymap, us_shiftkeymap, PS2KBD_KEYMAP_SIZE); + memcpy(keycap, us_keycap, PS2KBD_KEYMAP_SIZE); + memcpy(special_keys, us_special_keys, PS2KBD_KEYMAP_SIZE); + memcpy(control_map, us_control_map, PS2KBD_KEYMAP_SIZE); + memcpy(alt_map, us_alt_map, PS2KBD_KEYMAP_SIZE); + + ps2kbd_init_rpc(); + init_repeatthread(); + + ret = UsbRegisterDriver(&kbd_driver); + if(ret != USB_RC_OK) + { + printf("Error registering USB devices\n"); + return 1; + } + + printf("UsbRegisterDriver %d\n", ret); + + return 0; +} diff --git a/backends/platform/ps2/iop/rpckbd/src/us_keymap.h b/backends/platform/ps2/iop/rpckbd/src/us_keymap.h new file mode 100644 index 0000000000..57f0686cd3 --- /dev/null +++ b/backends/platform/ps2/iop/rpckbd/src/us_keymap.h @@ -0,0 +1,1579 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# $Id$ +# USB Keyboard Driver for PS2 +*/ + +#ifndef __US_KEYMAP_H__ +#define __US_KEYMAP_H__ + +/* Default US keymap */ + +u8 us_keymap[PS2KBD_KEYMAP_SIZE] = + { + 0, + 0, + 0, + 0, + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + 10, /* line feed */ + 0, /* Esc */ + 0x7,/* BS */ + 0x9, /* TAB */ + 0x20, + '-', + '=', + '[', + ']', + '\\', + '#', + ';', + '\'', + '`', + ',', + '.', + '/', + 0, /* CL */ + 0, // F1 + 0, // F2 + 0, // F3 + 0, // F4 + 0, // F5 + 0, // F6 + 0, // F7 + 0, // F8 + 0, // F9 + 0, // F10 + 0, // F11 + 0, // F12 + 0, // PrintScr + 0, // Scroll Lock + 0, // Pause + 0, // Insert + 0, // Home + 0, // Pg Up + 0, // Delete + 0, // End + 0, // Pg Down + 0, // Right + 0, // Left + 0, // Down + 0, // Up + 0, // Numlock + '/', // Keypad + '*', + '-', + '+', + 10, + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '.', + '\\', + 0, + 0, + '=', + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + +u8 us_shiftkeymap[PS2KBD_KEYMAP_SIZE] = + { + 0, + 0, + 0, + 0, + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + '!', + '@', + '#', + '$', + '%', + '^', + '&', + '*', + '(', + ')', + 10, /* line feed */ + 0, /* Esc */ + 0x7,/* BS */ + 0x9, /* TAB */ + 0x20, + '_', + '+', + '{', + '}', + '|', + '~', + ':', + '"', + '~', + '<', + '>', + '?', + 0, /* CL */ + 0, // F1 + 0, // F2 + 0, // F3 + 0, // F4 + 0, // F5 + 0, // F6 + 0, // F7 + 0, // F8 + 0, // F9 + 0, // F10 + 0, // F11 + 0, // F12 + 0, // PrintScr + 0, // Scroll Lock + 0, // Pause + 0, // Insert + 0, // Home + 0, // Pg Up + 0, // Delete + 0, // End + 0, // Pg Down + 0, // Right + 0, // Left + 0, // Down + 0, // Up + 0, // Numlock + '/', // Keypad + '*', + '-', + '+', + 10, + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '.', + '\\', + 0, + 0, + '=', + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + +u8 us_keycap[PS2KBD_KEYMAP_SIZE] = + { + 0, + 0, + 0, + 0, + 1, //a + 1, //b + 1, //c + 1, //d + 1, //e + 1, //f + 1,//g + 1,//h + 1,//i + 1,//j + 1,//k + 1,//l + 1,//m + 1,//n + 1,//o + 1,//p + 1,//q + 1,//r + 1,//s + 1,//t + 1,//u + 1,//v + 1,//w + 1,//x + 1,//y + 1,//z + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* line feed */ + 0, /* Esc */ + 0,/* BS */ + 0, /* TAB */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* CL */ + 0, // F1 + 0, // F2 + 0, // F3 + 0, // F4 + 0, // F5 + 0, // F6 + 0, // F7 + 0, // F8 + 0, // F9 + 0, // F10 + 0, // F11 + 0, // F12 + 0, // PrintScr + 0, // Scroll Lock + 0, // Pause + 0, // Insert + 0, // Home + 0, // Pg Up + 0, // Delete + 0, // End + 0, // Pg Down + 0, // Right + 0, // Left + 0, // Down + 0, // Up + 0, // Numlock + 0, // Keypad + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + +u8 us_special_keys[PS2KBD_KEYMAP_SIZE] = { + + 0, + 0, + 0, + 0, + 0, //a + 0, //b + 0, //c + 0, //d + 0, //e + 0, //f + 0,//g + 0,//h + 0,//i + 0,//j + 0,//k + 0,//l + 0,//m + 0,//n + 0,//o + 0,//p + 0,//q + 0,//r + 0,//s + 0,//t + 0,//u + 0,//v + 0,//w + 0,//x + 0,//y + 0,//z + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* line feed */ + 0x1B, /* Esc */ + 0,/* BS */ + 0, /* TAB */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* CL */ + 1, // F1 + 2, // F2 + 3, // F3 + 4, // F4 + 5, // F5 + 6, // F6 + 7, // F7 + 8, // F8 + 9, // F9 + 10, // F10 + 11, // F11 + 12, // F12 + 32, // PrintScr + 33, // Scroll Lock + 34, // Pause + 35, // Insert + 36, // Home + 37, // Pg Up + 38, // Delete + 39, // End + 40, // Pg Down + 41, // Right + 42, // Left + 43, // Down + 44, // Up + 0, // Numlock + 0, // Keypad / + 0, // Keypad * + 0, // Keypad - + 0, // Keypad + + 0, // Keypad Enter + 39, // Keypad 1/End + 43, // Keypad 2/Down + 40, // Keypad 3/PageDn + 42, // Keypad 4/Left + 0, // Keypad 5 + 41, // Keypad 6/Right + 36, // Keypad 7/Home + 44, // Keypad 8/Up + 37, // Keypad 9/PageUp + 35, // Keypad 0/Insert + 38, // Keypad ./Delete + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + +u8 us_control_map[PS2KBD_KEYMAP_SIZE] = { + + 0, + 0, + 0, + 0, + 1, //a + 2, //b + 3, //c + 4, //d + 5, //e + 6, //f + 7,//g + 8,//h + 9,//i + 10,//j + 11,//k + 12,//l + 13,//m + 14,//n + 15,//o + 16,//p + 17,//q + 18,//r + 19,//s + 20,//t + 21,//u + 22,//v + 23,//w + 24,//x + 25,//y + 26,//z + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* line feed */ + 0, /* Esc */ + 0,/* BS */ + 0, /* TAB */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* CL */ + 0, // F1 + 0, // F2 + 0, // F3 + 0, // F4 + 0, // F5 + 0, // F6 + 0, // F7 + 0, // F8 + 0, // F9 + 0, // F10 + 0, // F11 + 0, // F12 + 0, // PrintScr + 0, // Scroll Lock + 0, // Pause + 0, // Insert + 0, // Home + 0, // Pg Up + 0, // Delete + 0, // End + 0, // Pg Down + 0, // Right + 0, // Left + 0, // Down + 0, // Up + 0, // Numlock + 0, // Keypad + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 +}; + +u8 us_alt_map[PS2KBD_KEYMAP_SIZE] = { + + 0, + 0, + 0, + 0, + 128, //a + 129, //b + 130, //c + 131, //d + 132, //e + 133, //f + 134,//g + 135,//h + 136,//i + 137,//j + 138,//k + 139,//l + 140,//m + 141,//n + 142,//o + 143,//p + 144,//q + 145,//r + 146,//s + 147,//t + 148,//u + 149,//v + 150,//w + 151,//x + 152,//y + 154,//z + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, /* line feed */ + 0, /* Esc */ + 0,/* BS */ + 0, /* TAB */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* CL */ + 0, // F1 + 0, // F2 + 0, // F3 + 0, // F4 + 0, // F5 + 0, // F6 + 0, // F7 + 0, // F8 + 0, // F9 + 0, // F10 + 0, // F11 + 0, // F12 + 0, // PrintScr + 0, // Scroll Lock + 0, // Pause + 0, // Insert + 0, // Home + 0, // Pg Up + 0, // Delete + 0, // End + 0, // Pg Down + 0, // Right + 0, // Left + 0, // Down + 0, // Up + 0, // Numlock + 0, // Keypad + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + +#endif diff --git a/backends/platform/ps2/irxboot.cpp b/backends/platform/ps2/irxboot.cpp index 327e5bdc71..65d1e243eb 100644 --- a/backends/platform/ps2/irxboot.cpp +++ b/backends/platform/ps2/irxboot.cpp @@ -43,7 +43,7 @@ IrxFile irxFiles[] = { { "PADMAN", BIOS, NOTHING, NULL, 0 }, { "LIBSD", BIOS, NOTHING, NULL, 0 }, - { "IOMANX.IRX", SYSTEM | NOT_HOST, NOTHING, NULL, 0 }, // already loaded by ps2link + { "IOMANX.IRX", SYSTEM /*| NOT_HOST*/, NOTHING, NULL, 0 }, // already loaded by ps2link { "FILEXIO.IRX", SYSTEM, NOTHING, NULL, 0 }, { "CODYVDFS.IRX", SYSTEM, NOTHING, NULL, 0 }, { "SJPCM.IRX", SYSTEM, NOTHING, NULL, 0 }, diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp index 28ced7b345..d4dd9aedcf 100644 --- a/backends/platform/ps2/systemps2.cpp +++ b/backends/platform/ps2/systemps2.cpp @@ -54,9 +54,11 @@ #include "graphics/surface.h" #include "graphics/font.h" #include "backends/timer/default/default-timer.h" -#include "sound/mixer.h" +#include "sound/mixer_intern.h" #include "common/events.h" #include "backends/platform/ps2/ps2debug.h" +#include "backends/fs/ps2/ps2-fs-factory.h" + // asm("mfc0 %0, $9\n" : "=r"(tickStart)); extern void *_gp; @@ -309,7 +311,9 @@ OSystem_PS2::OSystem_PS2(const char *elfPath) { void OSystem_PS2::init(void) { sioprintf("Timer...\n"); _scummTimerManager = new DefaultTimerManager(); - _scummMixer = new Audio::Mixer(); + _scummMixer = new Audio::MixerImpl(this); + _scummMixer->setOutputRate(44100); + _scummMixer->setReady(true); initTimer(); sioprintf("Starting SavefileManager\n"); @@ -410,7 +414,8 @@ void OSystem_PS2::soundThread(void) { // we have to produce more samples, call sound mixer // the scratchpad at 0x70000000 is used as temporary soundbuffer //_scummSoundProc(_scummSoundParam, (uint8*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); - Audio::Mixer::mixCallback(_scummMixer, (byte*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); + // Audio::Mixer::mixCallback(_scummMixer, (byte*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); + _scummMixer->mixCallback((byte*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); // demux data into 2 buffers, L and R __asm__ ( @@ -534,10 +539,6 @@ Common::TimerManager *OSystem_PS2::getTimerManager() { return _scummTimerManager; } -int OSystem_PS2::getOutputSampleRate(void) const { - return 48000; -} - Audio::Mixer *OSystem_PS2::getMixer() { return _scummMixer; } @@ -546,6 +547,10 @@ Common::SaveFileManager *OSystem_PS2::getSavefileManager(void) { return _saveManager; } +FilesystemFactory *OSystem_PS2::getFilesystemFactory() { + return &Ps2FilesystemFactory::instance(); +} + void OSystem_PS2::setShakePos(int shakeOffset) { _screen->setShakePos(shakeOffset); } diff --git a/backends/platform/ps2/systemps2.h b/backends/platform/ps2/systemps2.h index 9dbe9be553..08975ab2c8 100644 --- a/backends/platform/ps2/systemps2.h +++ b/backends/platform/ps2/systemps2.h @@ -33,6 +33,7 @@ class DefaultTimerManager; class Gs2dScreen; class Ps2Input; class Ps2SaveFileManager; +// class Ps2FilesystemFactory; struct IrxReference; #define MAX_MUTEXES 16 @@ -48,7 +49,7 @@ namespace Common { }; namespace Audio { - class Mixer; + class MixerImpl; }; class OSystem_PS2 : public OSystem { @@ -87,7 +88,6 @@ public: virtual bool pollEvent(Common::Event &event); virtual Audio::Mixer *getMixer(); - virtual int getOutputSampleRate(void) const; virtual bool openCD(int drive); virtual bool pollCD(); @@ -112,6 +112,7 @@ public: virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b); virtual Common::SaveFileManager *getSavefileManager(); + virtual FilesystemFactory *getFilesystemFactory(); virtual void getTimeAndDate(struct tm &t) const; @@ -133,7 +134,7 @@ private: void readRtcTime(void); DefaultTimerManager *_scummTimerManager; - Audio::Mixer *_scummMixer; + Audio::MixerImpl *_scummMixer; bool _mouseVisible; diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 290fe63663..76ac91c282 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -191,7 +191,7 @@ OSystem_SDL::OSystem_SDL() OSystem_SDL::~OSystem_SDL() { SDL_RemoveTimer(_timerID); - SDL_CloseAudio(); + closeMixer(); free(_dirtyChecksums); free(_currentPalette); @@ -199,7 +199,6 @@ OSystem_SDL::~OSystem_SDL() { free(_mouseData); delete _savefile; - delete _mixer; delete _timer; } @@ -306,7 +305,7 @@ void OSystem_SDL::quit() { SDL_ShowCursor(SDL_ENABLE); SDL_RemoveTimer(_timerID); - SDL_CloseAudio(); + closeMixer(); free(_dirtyChecksums); free(_currentPalette); @@ -314,7 +313,6 @@ void OSystem_SDL::quit() { free(_mouseData); delete _savefile; - delete _mixer; delete _timer; SDL_Quit(); @@ -389,14 +387,110 @@ void OSystem_SDL::deleteMutex(MutexRef mutex) { #pragma mark --- Audio --- #pragma mark - +#ifdef MIXER_DOUBLE_BUFFERING + +void OSystem_SDL::mixerProducerThread() { + byte nextSoundBuffer; + + SDL_LockMutex(_soundMutex); + while (true) { + // Wait till we are allowed to produce data + SDL_CondWait(_soundCond, _soundMutex); + + if (_soundThreadShouldQuit) + break; + + // Generate samples and put them into the next buffer + nextSoundBuffer = _activeSoundBuf ^ 1; + _mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize); + + // Swap buffers + _activeSoundBuf = nextSoundBuffer; + } + SDL_UnlockMutex(_soundMutex); +} + +int SDLCALL OSystem_SDL::mixerProducerThreadEntry(void *arg) { + OSystem_SDL *this_ = (OSystem_SDL *)arg; + assert(this_); + this_->mixerProducerThread(); + return 0; +} + + +void OSystem_SDL::initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize) { + _soundThreadIsRunning = false; + _soundThreadShouldQuit = false; + + // Create mutex and condition variable + _soundMutex = SDL_CreateMutex(); + _soundCond = SDL_CreateCond(); + + // Create two sound buffers + _activeSoundBuf = 0; + _soundBufSize = bufSize; + _soundBuffers[0] = (byte *)calloc(1, bufSize); + _soundBuffers[1] = (byte *)calloc(1, bufSize); + + _soundThreadIsRunning = true; + + // Finally start the thread + _soundThread = SDL_CreateThread(mixerProducerThreadEntry, this); +} + +void OSystem_SDL::deinitThreadedMixer() { + // Kill thread?? _soundThread + + if (_soundThreadIsRunning) { + // Signal the producer thread to end, and wait for it to actually finish. + _soundThreadShouldQuit = true; + SDL_CondBroadcast(_soundCond); + SDL_WaitThread(_soundThread, NULL); + + // Kill the mutex & cond variables. + // Attention: AT this point, the mixer callback must not be running + // anymore, else we will crash! + SDL_DestroyMutex(_soundMutex); + SDL_DestroyCond(_soundCond); + + _soundThreadIsRunning = false; + + free(_soundBuffers[0]); + free(_soundBuffers[1]); + } +} + + +void OSystem_SDL::mixCallback(void *arg, byte *samples, int len) { + OSystem_SDL *this_ = (OSystem_SDL *)arg; + assert(this_); + assert(this_->_mixer); + + assert((int)this_->_soundBufSize == len); + + // Lock mutex, to ensure our data is not overwritten by the producer thread + SDL_LockMutex(this_->_soundMutex); + + // Copy data from the current sound buffer + memcpy(samples, this_->_soundBuffers[this_->_activeSoundBuf], len); + + // Unlock mutex and wake up the produced thread + SDL_UnlockMutex(this_->_soundMutex); + SDL_CondSignal(this_->_soundCond); +} + +#else + void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) { OSystem_SDL *this_ = (OSystem_SDL *)sys; assert(this_); + assert(this_->_mixer); - if (this_->_mixer) - this_->_mixer->mixCallback(samples, len); + this_->_mixer->mixCallback(samples, len); } +#endif + void OSystem_SDL::setupMixer() { SDL_AudioSpec desired; SDL_AudioSpec obtained; @@ -443,10 +537,31 @@ void OSystem_SDL::setupMixer() { // Tell the mixer that we are ready and start the sound processing _mixer->setOutputRate(_samplesPerSec); _mixer->setReady(true); + +#ifdef MIXER_DOUBLE_BUFFERING + initThreadedMixer(_mixer, obtained.samples * 4); +#endif + + // start the sound system SDL_PauseAudio(0); } } +void OSystem_SDL::closeMixer() { + if (_mixer) + _mixer->setReady(false); + + SDL_CloseAudio(); + + delete _mixer; + _mixer = 0; + +#ifdef MIXER_DOUBLE_BUFFERING + deinitThreadedMixer(); +#endif + +} + Audio::Mixer *OSystem_SDL::getMixer() { assert(_mixer); return _mixer; diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 8a94a17b00..4ad588f5f5 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -51,6 +51,15 @@ namespace Common { #define USE_OSD 1 #endif +#if defined(MACOSX) +// On Mac OS X, we need to double buffer the audio buffer, else anything +// which produces sampled data with high latency (like the MT-32 emulator) +// will sound terribly. +// This could be enabled for more / most ports in the future, but needs some +// testing. +#define MIXER_DOUBLE_BUFFERING 1 +#endif + enum { GFX_NORMAL = 0, @@ -137,6 +146,8 @@ public: virtual void setupMixer(); static void mixCallback(void *s, byte *samples, int len); + virtual void closeMixer(); + virtual Audio::Mixer *getMixer(); // Poll CD status @@ -369,6 +380,23 @@ protected: */ MutexRef _graphicsMutex; +#ifdef MIXER_DOUBLE_BUFFERING + SDL_mutex *_soundMutex; + SDL_cond *_soundCond; + SDL_Thread *_soundThread; + bool _soundThreadIsRunning; + bool _soundThreadShouldQuit; + + byte _activeSoundBuf; + uint _soundBufSize; + byte *_soundBuffers[2]; + + void mixerProducerThread(); + static int SDLCALL mixerProducerThreadEntry(void *arg); + void initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize); + void deinitThreadedMixer(); +#endif + Common::SaveFileManager *_savefile; Audio::MixerImpl *_mixer; @@ -377,7 +405,7 @@ protected: Common::TimerManager *_timer; - +protected: void addDirtyRgnAuto(const byte *buf); void makeChecksums(const byte *buf); diff --git a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl index 1e5e4dc0c8..5d85fc03a2 100644 --- a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl +++ b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl @@ -226,28 +226,31 @@ $VariationSets{'ALL'}{'all'} = "$DefaultFeatures @WorkingEngines @EnablableSubEngines"; # now one for each ready-for-release engine - + if (0) + { foreach (@WorkingEngines) { $VariationSets{'ALL'}{$_} = "$DefaultFeatures $_"; } # for scumm, we need to add 2 features: - $VariationSets{'ALL'}{'scumm'} .= " scumm_7_8 he"; - + #$VariationSets{'ALL'}{'scumm'} .= " scumm_7_8 he"; + } + # now one for each not-ready-for-release-or-testing engine - + if (0) + { foreach (@TestingEngines) { $VariationSets{'ALL'}{"test_$_"} = "$DefaultFeatures $_"; } - + } # below here you could specify weird & experimental combinations, non-ready engines # a small version of the saga engine, because it is so big (no tremor,mad,zlib) - $VariationSets{'ALL'}{'saga_mini'} = "saga"; + #$VariationSets{'ALL'}{'saga_mini'} = "saga"; # a smaller version of scumm without support for v7, v8 and HE games - $VariationSets{'ALL'}{'scumm_no78he'} = "$DefaultFeatures scumm"; + #$VariationSets{'ALL'}{'scumm_no78he'} = "$DefaultFeatures scumm"; # maybe you feel lucky and want to test the sword engines? :P #$VariationSets{'S60v2'}{'test_sword'} = "$DefaultFeatures mpeg2 sword1 sword2"; diff --git a/backends/platform/symbian/src/SymbianOS.cpp b/backends/platform/symbian/src/SymbianOS.cpp index dfeb24d825..660b0c69ed 100644 --- a/backends/platform/symbian/src/SymbianOS.cpp +++ b/backends/platform/symbian/src/SymbianOS.cpp @@ -33,7 +33,7 @@ #include "gui/Actions.h" #include "gui/Key.h" #include "gui/message.h" - +#include "sound/mixer_intern.h" #include "..\..\sdl\main.cpp" #ifdef SAMPLES_PER_SEC_8000 // the GreanSymbianMMP format cannot handle values for defines :( @@ -42,10 +42,22 @@ #define SAMPLES_PER_SEC 16000 #endif +#define KInputBufferLength 128 +// Symbian libc file functionality in order to provide shared file handles +struct TSymbianFileEntry { + RFile iFileHandle; + char iInputBuffer[KInputBufferLength]; + TInt iInputBufferLen; + TInt iInputPos; +}; + +#define FILE void ////////// extern "C" /////////////////////////////////////////////////// namespace Symbian { + + // Show a simple Symbian Info win with Msg & exit void FatalError(const char *msg) { TPtrC8 msgPtr((const TUint8 *)msg); @@ -246,9 +258,9 @@ void OSystem_SDL_Symbian::symbianMixCallback(void *sys, byte *samples, int len) if (!this_->_mixer) return; -#ifdef S60 +#if defined (S60) && !defined(S60V3) // If not stereo then we need to downmix - if (_channels != 2) { + if (this_->_mixer->_channels != 2) { this_->_mixer->mixCallback(_stereo_mix_buffer, len * 2); int16 *bitmixDst = (int16 *)samples; @@ -443,15 +455,9 @@ void OSystem_SDL_Symbian::initZones() { } } -// Symbian libc file functionality in order to provide shared file handles -struct TSymbianFileEntry { - RFile iFileHandle; -}; - -#define FILE void - FILE* symbian_fopen(const char* name, const char* mode) { TSymbianFileEntry* fileEntry = new TSymbianFileEntry; + fileEntry->iInputPos = KErrNotFound; if (fileEntry != NULL) { TInt modeLen = strlen(mode); @@ -509,9 +515,71 @@ void symbian_fclose(FILE* handle) { } size_t symbian_fread(const void* ptr, size_t size, size_t numItems, FILE* handle) { - TPtr8 pointer( (unsigned char*) ptr, size*numItems); + TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle)); + TUint32 totsize = size*numItems; + TPtr8 pointer ( (unsigned char*) ptr, totsize); + + // Nothing cached and we want to load at least KInputBufferLength bytes + if(totsize >= KInputBufferLength) { + TUint32 totLength = 0; + if(entry->iInputPos != KErrNotFound) + { + TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer+entry->iInputPos, entry->iInputBufferLen - entry->iInputPos, KInputBufferLength); + pointer.Append(cacheBuffer); + entry->iInputPos = KErrNotFound; + totLength+=pointer.Length(); + pointer.Set(totLength+(unsigned char*) ptr, 0, totsize-totLength); + } - ((TSymbianFileEntry*)(handle))->iFileHandle.Read(pointer); + entry->iFileHandle.Read(pointer); + totLength+=pointer.Length(); + + pointer.Set((unsigned char*) ptr, totLength, totsize); + + } + else { + // Nothing in buffer + if(entry->iInputPos == KErrNotFound) { + TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer, KInputBufferLength); + entry->iFileHandle.Read(cacheBuffer); + + if(cacheBuffer.Length() >= totsize) { + pointer.Copy(cacheBuffer.Left(totsize)); + entry->iInputPos = totsize; + entry->iInputBufferLen = cacheBuffer.Length(); + } + else { + pointer.Copy(cacheBuffer); + entry->iInputPos = KErrNotFound; + } + + } + else { + TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer, entry->iInputBufferLen, KInputBufferLength); + + if(entry->iInputPos+totsize < entry->iInputBufferLen) { + pointer.Copy(cacheBuffer.Mid(entry->iInputPos, totsize)); + entry->iInputPos+=totsize; + } + else { + + pointer.Copy(cacheBuffer.Mid(entry->iInputPos, entry->iInputBufferLen-entry->iInputPos)); + cacheBuffer.SetLength(0); + entry->iFileHandle.Read(cacheBuffer); + + if(cacheBuffer.Length() >= totsize-pointer.Length()) { + TUint32 restSize = totsize-pointer.Length(); + pointer.Append(cacheBuffer.Left(restSize)); + entry->iInputPos = restSize; + entry->iInputBufferLen = cacheBuffer.Length(); + } + else { + pointer.Append(cacheBuffer); + entry->iInputPos = KErrNotFound; + } + } + } + } return pointer.Length()/size; } @@ -519,6 +587,7 @@ size_t symbian_fread(const void* ptr, size_t size, size_t numItems, FILE* handle size_t symbian_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle) { TPtrC8 pointer( (unsigned char*) ptr, size*numItems); + ((TSymbianFileEntry*)(handle))->iInputPos = KErrNotFound; if (((TSymbianFileEntry*)(handle))->iFileHandle.Write(pointer) == KErrNone) { return numItems; } @@ -528,12 +597,18 @@ size_t symbian_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handl bool symbian_feof(FILE* handle) { TInt pos = 0; - if (((TSymbianFileEntry*)(handle))->iFileHandle.Seek(ESeekCurrent, pos) == KErrNone) { + TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle)); + + if (entry->iFileHandle.Seek(ESeekCurrent, pos) == KErrNone) { TInt size = 0; - if (((TSymbianFileEntry*)(handle))->iFileHandle.Size(size) == KErrNone) { - if (pos == size) + if (entry->iFileHandle.Size(size) == KErrNone) { + if(entry->iInputPos == KErrNotFound && pos == size) return true; + + if(entry->iInputPos != KErrNotFound && pos == size && entry->iInputPos == entry->iInputBufferLen) + return true; + return false; } } @@ -549,6 +624,7 @@ long int symbian_ftell(FILE* handle) { } int symbian_fseek(FILE* handle, long int offset, int whence) { + TSeek seekMode = ESeekStart; TInt pos = offset; @@ -564,6 +640,8 @@ int symbian_fseek(FILE* handle, long int offset, int whence) { break; } + + ((TSymbianFileEntry*)(handle))->iInputPos = KErrNotFound; return ((TSymbianFileEntry*)(handle))->iFileHandle.Seek(seekMode, pos); } diff --git a/backends/platform/wince/missing/missing.cpp b/backends/platform/wince/missing/missing.cpp index 86d93dcb88..c760b1f7df 100644 --- a/backends/platform/wince/missing/missing.cpp +++ b/backends/platform/wince/missing/missing.cpp @@ -1,8 +1,34 @@ -/* MISSING.C - Implementation for standard and semi-standard C library calls missing in WinCE - environment. - by Vasyl Tsvirkunov -*/ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* Original code: + * Implementation for standard and semi-standard C library calls missing in WinCE + * environment. + * by Vasyl Tsvirkunov + */ + #include <windows.h> #include <tchar.h> @@ -17,19 +43,8 @@ #include "time.h" #include "dirent.h" -/* forward declaration */ - -#if _WIN32_WCE < 300 - -#define _STDAFX_H -#include "portdefs.h" - -#else - char *strdup(const char *strSource); -#endif - #ifdef __GNUC__ #define EXT_C extern "C" #else @@ -40,19 +55,27 @@ char *strdup(const char *strSource); void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { - size_t i; + // Perform binary search + size_t lo = 0; + size_t hi = nmemb; + while (lo < hi) { + size_t mid = (lo + hi) / 2; + const void *p = ((const char *)base) + mid * size; + int tmp = (*compar)(key, p); + if (tmp < 0) + hi = mid; + else if (tmp > 0) + lo = mid + 1; + else + return (void *)p; + } - for (i=0; i<nmemb; i++) - if (compar(key, (void*)((size_t)base + size * i)) == 0) - return (void*)((size_t)base + size * i); return NULL; } static WIN32_FIND_DATA wfd; -/* Very limited implementation of stat. Used by UI.C, MEMORY-P.C (latter is not critical) */ -int stat(const char *fname, struct stat *ss) -{ +int stat(const char *fname, struct stat *ss) { TCHAR fnameUnc[MAX_PATH+1]; HANDLE handle; int len; @@ -63,8 +86,7 @@ int stat(const char *fname, struct stat *ss) /* Special case (dummy on WinCE) */ len = strlen(fname); if (len >= 2 && fname[len-1] == '.' && fname[len-2] == '.' && - (len == 2 || fname[len-3] == '\\')) - { + (len == 2 || fname[len-3] == '\\')) { /* That's everything implemented so far */ memset(ss, 0, sizeof(struct stat)); ss->st_size = 1024; @@ -74,6 +96,7 @@ int stat(const char *fname, struct stat *ss) MultiByteToWideChar(CP_ACP, 0, fname, -1, fnameUnc, MAX_PATH); handle = FindFirstFile(fnameUnc, &wfd); + FindClose(handle); if (handle == INVALID_HANDLE_VALUE) return -1; else @@ -83,20 +106,16 @@ int stat(const char *fname, struct stat *ss) ss->st_size = wfd.nFileSizeLow; if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ss->st_mode |= S_IFDIR; - - FindClose(handle); } return 0; } char cwd[MAX_PATH+1] = ""; -EXT_C char *getcwd(char *buffer, int maxlen) -{ +EXT_C char *getcwd(char *buffer, int maxlen) { TCHAR fileUnc[MAX_PATH+1]; char* plast; - if (cwd[0] == 0) - { + if (cwd[0] == 0) { GetModuleFileName(NULL, fileUnc, MAX_PATH); WideCharToMultiByte(CP_ACP, 0, fileUnc, -1, cwd, MAX_PATH, NULL, NULL); plast = strrchr(cwd, '\\'); @@ -114,8 +133,7 @@ EXT_C char *getcwd(char *buffer, int maxlen) #ifdef __GNUC__ #undef GetCurrentDirectory #endif -EXT_C void GetCurrentDirectory(int len, char *buf) -{ +EXT_C void GetCurrentDirectory(int len, char *buf) { getcwd(buf,len); }; @@ -125,26 +143,22 @@ fully qualified paths refer to root folder rather than current folder (concept not implemented in CE). */ #undef fopen -EXT_C FILE *wce_fopen(const char* fname, const char* fmode) -{ +EXT_C FILE *wce_fopen(const char* fname, const char* fmode) { char fullname[MAX_PATH+1]; if (!fname || fname[0] == '\0') return NULL; - if (fname[0] != '\\' && fname[0] != '/') - { + if (fname[0] != '\\' && fname[0] != '/') { getcwd(fullname, MAX_PATH); strncat(fullname, "\\", MAX_PATH-strlen(fullname)-1); strncat(fullname, fname, MAX_PATH-strlen(fullname)-strlen(fname)); return fopen(fullname, fmode); - } - else + } else return fopen(fname, fmode); } /* Remove file by name */ -int remove(const char* path) -{ +int remove(const char* path) { TCHAR pathUnc[MAX_PATH+1]; MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH); return !DeleteFile(pathUnc); @@ -158,14 +172,22 @@ int _access(const char *path, int mode) { WIN32_FIND_DATA ffd; HANDLE h=FindFirstFile(fname, &ffd); + FindClose(h); if (h == INVALID_HANDLE_VALUE) return -1; //Can't find file - FindClose(h); - if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) - return 0; //Always return success if target is directory and exists + if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) { + // WORKAROUND: WinCE (or the emulator) sometimes returns bogus direcotry + // hits for files that don't exist. Checking for the same fname twice + // seems to weed out those false positives. + HANDLE h=FindFirstFile(fname, &ffd); + FindClose(h); + if (h == INVALID_HANDLE_VALUE) + return -1; //Can't find file + return 0; //Always return success if target is directory and exists + } switch (mode) { case 00: //Check existence return 0; @@ -183,8 +205,7 @@ int _access(const char *path, int mode) { #ifndef __GNUC__ /* Limited dirent implementation. Used by UI.C and DEVICES.C */ -DIR* opendir(const char* fname) -{ +DIR* opendir(const char* fname) { DIR* pdir; char fnameMask[MAX_PATH+1]; TCHAR fnameUnc[MAX_PATH+1]; @@ -209,13 +230,10 @@ DIR* opendir(const char* fname) strcpy(pdir->dd_name, fname); /* it has exactly enough space for fname and nul char */ MultiByteToWideChar(CP_ACP, 0, fnameMask, -1, fnameUnc, MAX_PATH); - if ((pdir->dd_handle = (long)FindFirstFile(fnameUnc, &wfd)) == (long)INVALID_HANDLE_VALUE) - { + if ((pdir->dd_handle = (long)FindFirstFile(fnameUnc, &wfd)) == (long)INVALID_HANDLE_VALUE) { free(pdir); return NULL; - } - else - { + } else { WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL); pdir->dd_dir.d_name = strdup(nameFound); @@ -224,34 +242,25 @@ DIR* opendir(const char* fname) return pdir; } -struct dirent* readdir(DIR* dir) -{ +struct dirent* readdir(DIR* dir) { char nameFound[MAX_PATH+1]; static struct dirent dummy; - if (dir->dd_stat == 0) - { + if (dir->dd_stat == 0) { dummy.d_name = "."; dummy.d_namlen = 1; dir->dd_stat ++; return &dummy; - } - else if (dir->dd_stat == 1) - { + } else if (dir->dd_stat == 1) { dummy.d_name = ".."; dummy.d_namlen = 2; dir->dd_stat ++; return &dummy; - } - else if (dir->dd_stat == 2) - { + } else if (dir->dd_stat == 2) { dir->dd_stat++; return &dir->dd_dir; - } - else - { - if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0) - { + } else { + if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0) { dir->dd_stat = -1; return NULL; } @@ -283,12 +292,6 @@ int closedir(DIR* dir) return 1; } -/* in our case unlink is the same as remove */ -int unlink(const char* path) -{ - return remove(path); -} - /* Make directory, Unix style */ void mkdir(char* dirname, int mode) { @@ -299,10 +302,8 @@ void mkdir(char* dirname, int mode) if (*path == '/') *path = '\\'; /* Run through the string and attempt creating all subdirs on the path */ - for (ptr = path+1; *ptr; ptr ++) - { - if (*ptr == '\\' || *ptr == '/') - { + for (ptr = path+1; *ptr; ptr ++) { + if (*ptr == '\\' || *ptr == '/') { *ptr = 0; MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH); CreateDirectory(pathUnc, 0); @@ -313,373 +314,40 @@ void mkdir(char* dirname, int mode) CreateDirectory(pathUnc, 0); } -/* Used in DEVICES.C and UI.C for some purpose. Not critical in this port */ -int system(const char* path) { return 0; } - -#if 0 - -char *tmpnam(char *string) -{ - TCHAR pTemp[MAX_PATH+1]; - static char buffer[MAX_PATH+1]; - GetTempFileName(TEXT("."), TEXT("A8_"), 0, pTemp); - WideCharToMultiByte(CP_ACP, 0, pTemp, -1, buffer, MAX_PATH, NULL, NULL); - - if (string) - { - strcpy(string, buffer); - return string; - } - else - return buffer; -} - -FILE *tmpfile() -{ - TCHAR pTemp[MAX_PATH+1]; - if (!GetTempFileName(TEXT("."), TEXT("A8_"), 0, pTemp)) - return _wfopen(pTemp, TEXT("w+b")); - else - return 0; -} - -#endif - -void rewind(FILE *stream) -{ - fseek(stream, 0, SEEK_SET); -} - - -#if _WIN32_WCE < 300 - -int isalnum(int c) { - return ((c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9')); -} - -char *_strdup(const char *strSource) -#else char *strdup(const char *strSource) -#endif { char* buffer; - buffer = (char*)malloc(strlen(strSource)+1); + size_z len = strlen(strSource)+1; + buffer = (char*)malloc(len); if (buffer) - strcpy(buffer, strSource); + memcpy(buffer, strSource, len); return buffer; } -/* Very limited implementation of sys/time.h */ -void usleep(long usec) -{ - long msec = usec/1000; - if (msec <= 0) - Sleep(0); - else - Sleep(msec); -} - -/* This may provide for better sync mechanism */ -unsigned int clock() -{ - return GetTickCount(); -} - -/* And why do people use this? */ -#if _WIN32_WCE >= 300 -void abort() -{ - exit(1); -} -#endif - -/* -IMHO, no project should use this one, it is not portable at all. This implementation -at least allows some projects to work. -*/ -char* getenv(char* name) -{ - static char buffer[MAX_PATH+1]; - if (strcmp(name, "HOME") == 0 || strcmp(name, "HOMEDIR") == 0) - { - getcwd(buffer, MAX_PATH); - return buffer; - } - else - return ""; -} - -#if _WIN32_WCE < 300 || defined(_TEST_HPC_STDIO) - -void *calloc(size_t n, size_t s) { - void *result = malloc(n * s); - if (result) - memset(result, 0, n * s); - - return result; -} - -char *strpbrk(const char *s, const char *accept) { - int i; - - if (!s || !accept) - return NULL; - - for (i=0; i<strlen(s); i++) { - int j; - for (j=0; j<strlen(accept); j++) - if (s[i] == accept[j]) - return (char*)&s[i]; - } - - return NULL; -} - -#ifndef _TEST_HPC_STDIO - -int isdigit(int c) { - return (c >='0' && c <= '9'); -} - -int isprint(int c) { - return (c >= ' ' && c <= '~'); -} - -int isspace(int c) { - return (c == ' '); -} - -#endif - -#ifndef WIN32_PLATFORM_HPCPRO - - -int printf(const char *format, ...) { - // useless anyway :) - return 0; -} - -FILE *fopen(const char *path, const char *mode) { - TCHAR tempo[MAX_PATH]; - HANDLE result; - bool writeAccess = (mode[0] == 'W' || mode[0] == 'w'); - - MultiByteToWideChar(CP_ACP, 0, path, strlen(path) + 1, tempo, sizeof(tempo)); - - result = CreateFile(tempo, ( writeAccess ? GENERIC_WRITE : GENERIC_READ), 0, NULL, (writeAccess ? CREATE_ALWAYS : OPEN_EXISTING), FILE_ATTRIBUTE_NORMAL, NULL); - if (result == INVALID_HANDLE_VALUE) - return NULL; - else - return (FILE*)result; -} - -FILE * _wfopen(const TCHAR *path, const TCHAR *mode) { - HANDLE result; - bool writeAccess = (mode[0] == 'W' || mode[0] == 'w'); - result = CreateFile(path, ( writeAccess ? GENERIC_WRITE : GENERIC_READ), 0, NULL, (writeAccess ? CREATE_ALWAYS : OPEN_EXISTING), FILE_ATTRIBUTE_NORMAL, NULL); - if (result == INVALID_HANDLE_VALUE) - return NULL; - else - return (FILE*)result; -} - -FILE *_wfreopen(const TCHAR *path, const TCHAR *mode, FILE *stream) { - fclose(stream); - stream = _wfopen(path, mode); - return stream; -} - -int fclose(FILE *stream) { - CloseHandle((HANDLE)stream); - return 1; -} - -int fseek(FILE *stream, long offset, int whence) { - SetFilePointer((HANDLE)stream, offset, NULL, (whence == SEEK_CUR ? FILE_CURRENT : whence == SEEK_END ? FILE_END : FILE_BEGIN)); - return 0; -} - -long ftell(FILE *stream) { - return (SetFilePointer((HANDLE)stream, 0, NULL, FILE_CURRENT)); -} - -size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { - DWORD sizeWritten; - - WriteFile((HANDLE)stream, ptr, size * nmemb, &sizeWritten, NULL); - - if (size != 0) - return sizeWritten / size; - else - return 0; -} - -size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { - DWORD sizeRead; - - ReadFile((HANDLE)stream, ptr, size * nmemb, &sizeRead, NULL); - - if (size != 0) - return sizeRead / size; - else - return 0; -} - -int fgetc(FILE *stream) { - unsigned char c; - if (fread(&c, 1, 1, stream) != 1) - return -1; - else - return c; -} - -char *fgets(char *s, int size, FILE *stream) { - int i = 0; - char tempo[1]; - - memset(s, 0, size); - while (fread(tempo, 1, 1, stream)) { - //if (tempo[0] == '\r') - // break; - if (tempo[0] == '\r') - continue; - s[i++] = tempo[0]; - if (tempo[0] == '\n') - break; - if (i == size) - break; - } - if (!i) - return NULL; - else - return s; -} - -int feof(FILE *stream) { - DWORD fileSize; - DWORD filePos; - fileSize = GetFileSize((HANDLE)stream, NULL); - filePos = SetFilePointer((HANDLE)stream, 0, 0, FILE_CURRENT); - return (filePos == 0xFFFFFFFF || filePos > (fileSize - 1)); -} - -int ferror(FILE *stream) { - return 0; // FIXME ! -} - -int fprintf(FILE *stream, const char *format, ...) { - char buf[1024]; - va_list va; - - va_start(va, format); - vsnprintf(buf, 1024, format, va); - va_end(va); - - if (buf[strlen(buf) - 1] == '\n') { - int i = strlen(buf) - 1; - buf[i] = '\r'; - buf[i + 1] = '\n'; - buf[i + 2] = 0; - } - - return fwrite(buf, 1, strlen(buf), stream); -} - -FILE* _getstdfilex(int) { - return NULL; -} - -void clearerr(FILE *stream) { -} - -int fflush(FILE *stream) { - return 0; -} - -#endif - -int stricmp( const char *string1, const char *string2 ) { - char src[4096]; - char dest[4096]; - int i; - - for (i=0; i<strlen(string1); i++) - if (string1[i] >= 'A' && string1[i] <= 'Z') - src[i] = string1[i] + 32; - else - src[i] = string1[i]; - src[i] = 0; - - for (i=0; i<strlen(string2); i++) - if (string2[i] >= 'A' && string2[i] <= 'Z') - dest[i] = string2[i] + 32; - else - dest[i] = string2[i]; - dest[i] = 0; - - return strcmp(src, dest); -} - -char *strrchr(const char *s, int c) { - int i; - - for (i = strlen(s) - 1; i > 0; i--) - if (s[i] == c) - return (char*)(s + i); - - return NULL; -} - -long int strtol(const char *nptr, char **endptr, int base) { - // not correct but that's all we are using - - long int result; - sscanf(nptr, "%ld", &result); - return result; -} - - -#endif - - // gcc build only functions follow #else // defined(__GNUC__) #ifndef __MINGW32CE__ -int islower(int c) -{ +int islower(int c) { return (c>='a' && c<='z'); } -int isspace(int c) -{ +int isspace(int c) { return (c==' ' || c=='\f' || c=='\n' || c=='\r' || c=='\t' || c=='\v'); } -int isalpha(int c) -{ - return (islower(c) || (c>='A' && c<='Z')); +int isalpha(int c) { + return ((c>='a' && c<='z') || (c>='A' && c<='Z')); } -int isalnum(int c) -{ - return (isalpha(c) || (c>='0' && c<='9')); -} - -int isprint(int c) -{ - static char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~"; - int i = 0, flag = 0; - while ((punct[i] != 0) && (flag = (punct[i] != c))) - i++; - return (isalnum(c) || flag); +int isalnum(int c) { + return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')); } -extern "C" int atexit(void (*function)(void)) -{ - return 0; +int isprint(int c) { + //static const char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~"; + //return (isalnum(c) || strchr(punct, c)); + return (32 <= c && c <= 126); // based on BSD manpage } #endif diff --git a/base/game.cpp b/base/game.cpp index 9628543672..e65c891dc7 100644 --- a/base/game.cpp +++ b/base/game.cpp @@ -32,10 +32,10 @@ const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const Pla const PlainGameDescriptor *g = list; while (g->gameid) { if (0 == scumm_stricmp(gameid, g->gameid)) - break; + return g; g++; } - return g; + return 0; } void GameDescriptor::updateDesc(const char *extra) { diff --git a/base/game.h b/base/game.h index 18d7967388..b068c300ce 100644 --- a/base/game.h +++ b/base/game.h @@ -48,7 +48,7 @@ struct PlainGameDescriptor { /** * Given a list of PlainGameDescriptors, returns the first PlainGameDescriptor * matching the given gameid. If not match is found return 0. - * The end of the list marked by a PlainGameDescriptor with gameid equal to 0. + * The end of the list must marked by a PlainGameDescriptor with gameid equal to 0. */ const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list); diff --git a/base/internal_version.h b/base/internal_version.h index 069c20b4c9..c867532dd9 100644 --- a/base/internal_version.h +++ b/base/internal_version.h @@ -1 +1 @@ -#define SCUMMVM_VERSION "0.12.0svn" +#define SCUMMVM_VERSION "0.13.0svn" diff --git a/base/plugins.h b/base/plugins.h index 9d3ce97c3b..02116f6433 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -81,17 +81,11 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; #define STATIC_PLUGIN 1 #define DYNAMIC_PLUGIN 2 -// Note: The spaces around ENABLE_##ID have been added on purpose for -// MSVC. For some reason, MSVC tries to add the parenthesis after -// ENABLE_##ID to the check, thus making it false all the time. -// Please do NOT remove them, otherwise no engine plugins will be -// registered under MSVC - #define PLUGIN_ENABLED_STATIC(ID) \ - (defined( ENABLE_##ID ) && !PLUGIN_ENABLED_DYNAMIC(ID)) + (ENABLE_##ID && !PLUGIN_ENABLED_DYNAMIC(ID)) #define PLUGIN_ENABLED_DYNAMIC(ID) \ - (defined( ENABLE_##ID ) && (ENABLE_##ID == DYNAMIC_PLUGIN) && defined(DYNAMIC_MODULES)) + (ENABLE_##ID && (ENABLE_##ID == DYNAMIC_PLUGIN) && DYNAMIC_MODULES) /** * REGISTER_PLUGIN_STATIC is a convenience macro which is used to declare diff --git a/common/config-manager.cpp b/common/config-manager.cpp index 5afbbad4ae..59855cf6c9 100644 --- a/common/config-manager.cpp +++ b/common/config-manager.cpp @@ -176,7 +176,6 @@ void ConfigManager::loadFile(const String &filename) { if (!cfg_file.open(filename)) { printf("Creating configuration file: %s\n", filename.c_str()); } else { - char buf[MAXLINELEN]; String domain; String comment; int lineno = 0; @@ -184,20 +183,28 @@ void ConfigManager::loadFile(const String &filename) { // TODO: Detect if a domain occurs multiple times (or likewise, if // a key occurs multiple times inside one domain). - while (!cfg_file.eof()) { + while (!cfg_file.eof() && !cfg_file.ioFailed()) { lineno++; - if (!cfg_file.readLine(buf, MAXLINELEN)) - break; - if (buf[0] == '#') { + // Read a line + String line; + while (line.lastChar() != '\n') { + char buf[MAXLINELEN]; + if (!cfg_file.readLine_NEW(buf, MAXLINELEN)) + break; + line += buf; + } + + if (line.size() == 0) { + // Do nothing + } else if (line[0] == '#') { // Accumulate comments here. Once we encounter either the start // of a new domain, or a key-value-pair, we associate the value // of the 'comment' variable with that entity. - comment += buf; - comment += '\n'; - } else if (buf[0] == '[') { + comment += line; + } else if (line[0] == '[') { // It's a new domain which begins here. - char *p = buf + 1; + const char *p = line.c_str() + 1; // Get the domain name, and check whether it's valid (that // is, verify that it only consists of alphanumerics, // dashes and underscores). @@ -209,8 +216,8 @@ void ConfigManager::loadFile(const String &filename) { error("Config file buggy: missing ] in line %d", lineno); break; case ']': - *p = 0; - domain = buf + 1; + domain = String(line.c_str() + 1, p - (line.c_str() + 1)); + //domain = String(line.c_str() + 1, p); // TODO: Pending Common::String changes break; default: error("Config file buggy: Invalid character '%c' occured in domain name in line %d", *p, lineno); @@ -226,10 +233,14 @@ void ConfigManager::loadFile(const String &filename) { _domainSaveOrder.push_back(domain); } else { - // Skip leading & trailing whitespaces - char *t = rtrim(ltrim(buf)); - - // Skip empty lines + // This line should be a line with a 'key=value' pair, or an empty one. + + // Skip leading whitespaces + const char *t = line.c_str(); + while (isspace(*t)) + t++; + + // Skip empty lines / lines with only whitespace if (*t == 0) continue; @@ -238,13 +249,30 @@ void ConfigManager::loadFile(const String &filename) { error("Config file buggy: Key/value pair found outside a domain in line %d", lineno); } - // Split string at '=' into 'key' and 'value'. - char *p = strchr(t, '='); + // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter. + const char *p = strchr(t, '='); if (!p) error("Config file buggy: Junk found in line line %d: '%s'", lineno, t); - *p = 0; - String key = rtrim(t); - String value = ltrim(p + 1); + + // Trim spaces before the '=' to obtain the key + const char *p2 = p; + while (p2 > t && isspace(*(p2-1))) + p2--; + String key(t, p2 - t); + + // Skip spaces after the '=' + t = p + 1; + while (isspace(*t)) + t++; + + // Trim trailing spaces + p2 = t + strlen(t); + while (p2 > t && isspace(*(p2-1))) + p2--; + + String value(t, p2 - t); + + // Finally, store the key/value pair in the active domain set(key, value, domain); // Store comment diff --git a/common/file.cpp b/common/file.cpp index 386777e2c5..a1ea1aff77 100644 --- a/common/file.cpp +++ b/common/file.cpp @@ -452,10 +452,12 @@ bool File::isOpen() const { } bool File::ioFailed() const { + // TODO/FIXME: Just use ferror() here? return _ioFailed != 0; } void File::clearIOFailed() { + // TODO/FIXME: Just use clearerr() here? _ioFailed = false; } diff --git a/common/str.cpp b/common/str.cpp index ad48ef6087..a2e6e0c66d 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -43,32 +43,43 @@ static int computeCapacity(int len) { return ((len + 32 - 1) & ~0x1F) - 1; } -String::String(const char *str, uint32 len) -: _len(0), _str(_storage) { +String::String(const char *str) : _len(0), _str(_storage) { + if (str == 0) { + _storage[0] = 0; + _len = 0; + } else + initWithCStr(str, strlen(str)); +} + +String::String(const char *str, uint32 len) : _len(0), _str(_storage) { + initWithCStr(str, len); +} + +String::String(const char *beginP, const char *endP) : _len(0), _str(_storage) { + assert(endP >= beginP); + initWithCStr(beginP, endP - beginP); +} + +void String::initWithCStr(const char *str, uint32 len) { + assert(str); // Init _storage member explicitly (ie. without calling its constructor) // for GCC 2.95.x compatibility (see also tracker item #1602879). _storage[0] = 0; - if (str && *str) { - const uint32 tmp = strlen(str); - assert(len <= tmp); - if (len <= 0) - len = tmp; - _len = len; - - if (len >= _builtinCapacity) { - // Not enough internal storage, so allocate more - _extern._capacity = computeCapacity(len); - _extern._refCount = 0; - _str = (char *)malloc(_extern._capacity+1); - assert(_str != 0); - } - - // Copy the string into the storage area - memcpy(_str, str, len); - _str[len] = 0; + _len = len; + + if (len >= _builtinCapacity) { + // Not enough internal storage, so allocate more + _extern._capacity = computeCapacity(len); + _extern._refCount = 0; + _str = (char *)malloc(_extern._capacity+1); + assert(_str != 0); } + + // Copy the string into the storage area + memmove(_str, str, len); + _str[len] = 0; } String::String(const String &str) @@ -91,6 +102,8 @@ String::String(char c) _storage[0] = c; _storage[1] = 0; + // TODO/FIXME: There is no reason for the following check -- we *do* + // allow strings to contain 0 bytes! _len = (c == 0) ? 0 : 1; } @@ -130,11 +143,14 @@ String& String::operator =(const char *str) { uint32 len = strlen(str); ensureCapacity(len, false); _len = len; - memcpy(_str, str, len + 1); + memmove(_str, str, len + 1); return *this; } String &String::operator =(const String &str) { + if (&str == this) + return *this; + if (str.isStorageIntern()) { decRefCount(_extern._refCount); _len = str._len; diff --git a/common/str.h b/common/str.h index a92ec34fff..ae9cb992b6 100644 --- a/common/str.h +++ b/common/str.h @@ -96,10 +96,24 @@ public: static const char *emptyString; #endif + /** Construct a new empty string. */ String() : _len(0), _str(_storage) { _storage[0] = 0; } - String(const char *str, uint32 len = 0); + + /** Construct a new string from the given NULL-terminated C string. */ + String(const char *str); + + /** Construct a new string containing exactly len characters read from address str. */ + String(const char *str, uint32 len); + + /** Construct a new string containing the characters between beginP (including) and endP (excluding). */ + String(const char *beginP, const char *endP); + + /** Construct a copy of the given string. */ String(const String &str); + + /** Construct a string consisting of the given character. */ String(char c); + ~String(); String &operator =(const char *str); @@ -162,7 +176,7 @@ public: void toLowercase(); void toUppercase(); - + uint hash() const; public: @@ -189,6 +203,7 @@ protected: void ensureCapacity(uint32 new_len, bool keep_old); void incRefCount() const; void decRefCount(int *oldRefCount); + void initWithCStr(const char *str, uint32 len); }; // Append two strings to form a new (temp) string diff --git a/common/stream.cpp b/common/stream.cpp index ab9804d7b6..61166fd451 100644 --- a/common/stream.cpp +++ b/common/stream.cpp @@ -148,6 +148,61 @@ char *SeekableReadStream::readLine(char *buf, size_t bufSize) { return buf; } +char *SeekableReadStream::readLine_NEW(char *buf, size_t bufSize) { + assert(buf != 0 && bufSize > 1); + char *p = buf; + size_t len = 0; + char c = 0; + + // If end-of-file occurs before any characters are read, return NULL + // and the buffer contents remain unchanged. + if (eos() || ioFailed()) { + return 0; + } + + // Loop as long as the stream has not ended, there is still free + // space in the buffer, and the line has not ended + while (!eos() && len + 1 < bufSize && c != LF) { + c = readByte(); + + // If end-of-file occurs before any characters are read, return + // NULL and the buffer contents remain unchanged. If an error + /// occurs, return NULL and the buffer contents are indeterminate. + if (ioFailed() || (len == 0 && eos())) + return 0; + + // Check for CR or CR/LF + // * DOS and Windows use CRLF line breaks + // * Unix and OS X use LF line breaks + // * Macintosh before OS X used CR line breaks + if (c == CR) { + // Look at the next char -- is it LF? If not, seek back + c = readByte(); + if (c != LF && !eos()) + seek(-1, SEEK_CUR); + // Treat CR & CR/LF as plain LF + c = LF; + } + + *p++ = c; + len++; + } + + // FIXME: + // This should fix a bug while using readLine with Common::File + // it seems that it sets the eos flag after an invalid read + // and at the same time the ioFailed flag + // the config file parser fails out of that reason for the new themes + if (eos()) { + clearIOFailed(); + } + + // We always terminate the buffer if no error occured + *p = 0; + return buf; +} + + uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) { dataSize = MIN(dataSize, _end - _pos); diff --git a/common/stream.h b/common/stream.h index 313a695e82..4cf5fae114 100644 --- a/common/stream.h +++ b/common/stream.h @@ -304,13 +304,40 @@ public: * Read one line of text from a CR or CR/LF terminated plain text file. * This method is a rough analog of the (f)gets function. * + * @bug A main difference (and flaw) in this function is that there is no + * way to detect that a line exceeeds the length of the buffer. + * Code which needs this should use the new readLine_NEW() method instead. + * * @param buf the buffer to store into * @param bufSize the size of the buffer * @return a pointer to the read string, or NULL if an error occurred + * * @note The line terminator (CR or CR/LF) is stripped and not inserted * into the buffer. */ virtual char *readLine(char *buf, size_t bufSize); + + /** + * Reads at most one less than the number of characters specified + * by bufSize from the and stores them in the string buf. Reading + * stops when the end of a line is reached (CR, CR/LF or LF), at + * end-of-file or error. The newline, if any, is retained (CR and + * CR/LF are translated to LF = 0xA = '\n'). If any characters are + * read and there is no error, a `\0' character is appended to end + * the string. + * + * Upon successful completion, return a pointer to the string. If + * end-of-file occurs before any characters are read, returns NULL + * and the buffer contents remain unchanged. If an error occurs, + * returns NULL and the buffer contents are indeterminate. + * This method does not distinguish between end-of-file and error; + * callers muse use ioFailed() or eos() to determine which occurred. + * + * @param buf the buffer to store into + * @param bufSize the size of the buffer + * @return a pointer to the read string, or NULL if an error occurred + */ + virtual char *readLine_NEW(char *s, size_t bufSize); }; /** @@ -129,10 +129,10 @@ _srcdir=`dirname $0` if type mktemp > /dev/null 2>&1 ; then TMPO=`mktemp /tmp/scummvm-conf.XXXXXXXXXX` else - TMPO=${_srcdir}/scummvm-conf + TMPO=scummvm-conf fi TMPC=${TMPO}.cpp -TMPLOG=${_srcdir}/config.log +TMPLOG=config.log # For cross compiling _host="" diff --git a/dists/redhat/scummvm.spec b/dists/redhat/scummvm.spec index efde789ce3..1d3b2bce64 100644 --- a/dists/redhat/scummvm.spec +++ b/dists/redhat/scummvm.spec @@ -7,7 +7,7 @@ # Prologue information #------------------------------------------------------------------------------ Name : scummvm -Version : 0.12.0svn +Version : 0.13.0svn Release : 1 Summary : Graphic adventure game interpreter Group : Interpreters diff --git a/dists/scummvm.rc b/dists/scummvm.rc index 73763a1216..0fb2b87071 100644 --- a/dists/scummvm.rc +++ b/dists/scummvm.rc @@ -7,8 +7,8 @@ IDI_ICON ICON DISCARDABLE "../../icons/scummvm.ico" #endif VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,12,0,0 - PRODUCTVERSION 0,12,0,0 + FILEVERSION 0,13,0,0 + PRODUCTVERSION 0,13,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -25,13 +25,13 @@ BEGIN BEGIN VALUE "Comments", "Look! A three headed monkey (TM)! .. Nice use of the TM!\0" VALUE "FileDescription", "http://www.scummvm.org/\0" - VALUE "FileVersion", "0.12.0svn\0" + VALUE "FileVersion", "0.13.0svn\0" VALUE "InternalName", "scummvm\0" VALUE "LegalCopyright", "Copyright © 2001-2007 The ScummVM Team\0" VALUE "LegalTrademarks", "'SCUMM', and all SCUMM games are a TM of LucasArts. Simon The Sorcerer is a TM of AdventureSoft. Beneath a Steel Sky and Broken Sword are a TM of Revolution. Flight of the Amazon Queen is a TM of John Passfield and Steve Stamatiadis. \0" VALUE "OriginalFilename", "scummvm.exe\0" VALUE "ProductName", "ScummVM\0" - VALUE "ProductVersion", "0.12.0svn\0" + VALUE "ProductVersion", "0.13.0svn\0" END END BLOCK "VarFileInfo" diff --git a/dists/slackware/scummvm.SlackBuild b/dists/slackware/scummvm.SlackBuild index 415ee4c867..6ed0ed6e57 100755 --- a/dists/slackware/scummvm.SlackBuild +++ b/dists/slackware/scummvm.SlackBuild @@ -8,7 +8,7 @@ if [ "$TMP" = "" ]; then fi PKG=$TMP/package-scummvm -VERSION=0.12.0svn +VERSION=0.13.0svn ARCH=i486 BUILD=1 diff --git a/engines/agos/agos.h b/engines/agos/agos.h index fe1d36f281..49b4478ec7 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -1076,6 +1076,8 @@ protected: virtual void drawImage(VC10_state *state); void drawBackGroundImage(VC10_state *state); void drawVertImage(VC10_state *state); + void drawVertImageCompressed(VC10_state *state); + void drawVertImageUncompressed(VC10_state *state); void setMoveRect(uint16 x, uint16 y, uint16 width, uint16 height); diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index 9d3dea3ee1..25a4b919f4 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -744,10 +744,6 @@ void AGOSEngine_Simon1::drawImage(VC10_state *state) { } void AGOSEngine::drawBackGroundImage(VC10_state *state) { - const byte *src; - byte *dst; - uint h, i; - state->width = _screenWidth; if (_window3Flag == 1) { state->width = 0; @@ -755,15 +751,19 @@ void AGOSEngine::drawBackGroundImage(VC10_state *state) { state->y_skip = 0; } - src = state->srcPtr + (state->width * state->y_skip) + (state->x_skip * 8); - dst = state->surf_addr; + const byte* src = state->srcPtr + (state->width * state->y_skip) + (state->x_skip * 8); + byte* dst = state->surf_addr; state->draw_width *= 2; - h = state->draw_height; + uint h = state->draw_height; + const uint w = state->draw_width; + const byte paletteMod = state->paletteMod; do { - for (i = 0; i != state->draw_width; i++) - dst[i] = src[i] + state->paletteMod; + for (uint i = 0; i != w; i+=2) { + dst[i] = src[i] + paletteMod; + dst[i+1] = src[i+1] + paletteMod; + } dst += state->surf_pitch; src += state->width; } while (--h); @@ -771,63 +771,86 @@ void AGOSEngine::drawBackGroundImage(VC10_state *state) { void AGOSEngine::drawVertImage(VC10_state *state) { if (state->flags & kDFCompressed) { - uint w, h; - byte *src, *dst, *dstPtr; + drawVertImageCompressed(state); + } else { + drawVertImageUncompressed(state); + } +} - state->x_skip *= 4; /* reached */ +void AGOSEngine::drawVertImageUncompressed(VC10_state *state) { + assert ((state->flags & kDFCompressed) == 0) ; - state->dl = state->width; - state->dh = state->height; + const byte *src; + byte *dst; + uint count; - vc10_skip_cols(state); + src = state->srcPtr + (state->width * state->y_skip) * 8; + dst = state->surf_addr; + state->x_skip *= 4; - dstPtr = state->surf_addr; - if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */ - dstPtr += vcReadVar(252); - } - w = 0; - do { + do { + for (count = 0; count != state->draw_width; count++) { byte color; + color = (src[count + state->x_skip] / 16) + state->paletteMod; + if ((state->flags & kDFNonTrans) || color) + dst[count * 2] = color | state->palette; + color = (src[count + state->x_skip] & 15) + state->paletteMod; + if ((state->flags & kDFNonTrans) || color) + dst[count * 2 + 1] = color | state->palette; + } + dst += state->surf_pitch; + src += state->width * 8; + } while (--state->draw_height); +} - src = vc10_depackColumn(state); - dst = dstPtr; +void AGOSEngine::drawVertImageCompressed(VC10_state *state) { + assert (state->flags & kDFCompressed) ; + uint w, h; + + state->x_skip *= 4; /* reached */ - h = 0; + state->dl = state->width; + state->dh = state->height; + + vc10_skip_cols(state); + + byte *dstPtr = state->surf_addr; + if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */ + dstPtr += vcReadVar(252); + } + w = 0; + do { + byte color; + + const byte *src = vc10_depackColumn(state); + byte *dst = dstPtr; + + h = 0; + if (state->flags & kDFNonTrans) { + do { + byte colors = *src; + color = (colors / 16); + dst[0] = color | state->palette; + color = (colors & 15); + dst[1] = color | state->palette; + dst += state->surf_pitch; + src++; + } while (++h != state->draw_height); + } else { do { - color = (*src / 16); - if ((state->flags & kDFNonTrans) || color != 0) + byte colors = *src; + color = (colors / 16); + if (color != 0) dst[0] = color | state->palette; - color = (*src & 15); - if ((state->flags & kDFNonTrans) || color != 0) + color = (colors & 15); + if (color != 0) dst[1] = color | state->palette; dst += state->surf_pitch; src++; } while (++h != state->draw_height); - dstPtr += 2; - } while (++w != state->draw_width); - } else { - const byte *src; - byte *dst; - uint count; - - src = state->srcPtr + (state->width * state->y_skip) * 8; - dst = state->surf_addr; - state->x_skip *= 4; - - do { - for (count = 0; count != state->draw_width; count++) { - byte color; - color = (src[count + state->x_skip] / 16) + state->paletteMod; - if ((state->flags & kDFNonTrans) || color) - dst[count * 2] = color | state->palette; - color = (src[count + state->x_skip] & 15) + state->paletteMod; - if ((state->flags & kDFNonTrans) || color) - dst[count * 2 + 1] = color | state->palette; - } - dst += state->surf_pitch; - src += state->width * 8; - } while (--state->draw_height); - } + } + dstPtr += 2; + } while (++w != state->draw_width); } void AGOSEngine::drawImage(VC10_state *state) { diff --git a/engines/cine/cine.h b/engines/cine/cine.h index 710840c17e..06f2dfd982 100644 --- a/engines/cine/cine.h +++ b/engines/cine/cine.h @@ -94,6 +94,7 @@ public: Common::StringList _volumeResourceFiles; StringPtrHashMap _volumeEntriesMap; + TextHandler _textHandler; private: void initialize(void); @@ -107,6 +108,7 @@ private: extern CineEngine *g_cine; #define BOOT_PRC_NAME "AUTO00.PRC" +#define COPY_PROT_FAIL_PRC_NAME "L201.ANI" enum { VAR_MOUSE_X_MODE = 253, diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index 2b7f3b8890..1f868ccb75 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -337,7 +337,7 @@ int FWRenderer::drawChar(char character, int x, int y) { x += 5; } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) { idx = fontParamTable[(unsigned char)character].characterIdx; - drawSpriteRaw(textTable[idx][0], textTable[idx][1], 16, 8, _backBuffer, x, y); + drawSpriteRaw(g_cine->_textHandler.textTable[idx][0], g_cine->_textHandler.textTable[idx][1], 16, 8, _backBuffer, x, y); x += width + 1; } @@ -938,7 +938,7 @@ int OSRenderer::drawChar(char character, int x, int y) { x += 5; } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) { idx = fontParamTable[(unsigned char)character].characterIdx; - drawSpriteRaw2(textTable[idx][0], 0, 16, 8, _backBuffer, x, y); + drawSpriteRaw2(g_cine->_textHandler.textTable[idx][0], 0, 16, 8, _backBuffer, x, y); x += width + 1; } diff --git a/engines/cine/prc.cpp b/engines/cine/prc.cpp index 42dcf1b491..657edf96af 100644 --- a/engines/cine/prc.cpp +++ b/engines/cine/prc.cpp @@ -41,8 +41,9 @@ ScriptList objectScripts; /*! \todo Is script size of 0 valid? * \todo Fix script dump code + * @return Was the loading successful? */ -void loadPrc(const char *pPrcName) { +bool loadPrc(const char *pPrcName) { byte i; uint16 numScripts; byte *scriptPtr, *dataPtr; @@ -53,11 +54,11 @@ void loadPrc(const char *pPrcName) { scriptTable.clear(); // This is copy protection. Used to hang the machine - if (!scumm_stricmp(pPrcName, "L201.ANI")) { + if (!scumm_stricmp(pPrcName, COPY_PROT_FAIL_PRC_NAME)) { Common::Event event; event.type = Common::EVENT_RTL; g_system->getEventManager()->pushEvent(event); - return; + return false; } checkDataDisk(-1); @@ -110,6 +111,8 @@ void loadPrc(const char *pPrcName) { } } #endif + + return true; } } // End of namespace Cine diff --git a/engines/cine/prc.h b/engines/cine/prc.h index f5129d28b1..05bb240372 100644 --- a/engines/cine/prc.h +++ b/engines/cine/prc.h @@ -31,7 +31,7 @@ namespace Cine { extern ScriptList globalScripts; extern ScriptList objectScripts; -void loadPrc(const char *pPrcName); +bool loadPrc(const char *pPrcName); } // End of namespace Cine diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 148e673095..54a4976000 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1019,6 +1019,20 @@ int FWScript::o1_divVar() { } int FWScript::o1_compareVar() { + // WORKAROUND: A workaround for a script bug in script file CODE2.PRC + // in at least some of the Amiga and Atari ST versions of Future Wars. + // Fixes bug #2016647 (FW: crash with italian amiga version). A local + // variable 251 is compared against value 0 although it's quite apparent + // from the context in the script that instead global variable 251 should + // be compared against value 0. So looks like someone made a typo when + // making the scripts. Therefore we change that particular comparison + // from using the local variable 251 to using the global variable 251. + if (g_cine->getGameType() == Cine::GType_FW && scumm_stricmp(currentPrcName, "CODE2.PRC") == 0 && + (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) && + _script.getByte(_pos) == 251 && _script.getByte(_pos + 1) == 0 && _script.getWord(_pos + 2) == 0) { + return o1_compareGlobalVar(); + } + byte varIdx = getNextByte(); byte varType = getNextByte(); diff --git a/engines/cine/texte.cpp b/engines/cine/texte.cpp index 9b4b83f420..e4fd334926 100644 --- a/engines/cine/texte.cpp +++ b/engines/cine/texte.cpp @@ -31,8 +31,6 @@ namespace Cine { byte *textDataPtr; -byte textTable[256][2][16 * 8]; - const char **failureMessages; const CommandeType *defaultActionCommand; const CommandeType *systemMenu; @@ -77,14 +75,14 @@ void loadTextData(const char *pFileName, byte *pDestinationBuffer) { loadRelatedPalette(pFileName); for (i = 0; i < numCharacters; i++) { - gfxConvertSpriteToRaw(textTable[i][0], tempBuffer, 16, 8); - generateMask(textTable[i][0], textTable[i][1], 16 * 8, 0); + gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 16, 8); + generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 16 * 8, 0); tempBuffer += dataSize; } } else { for (i = 0; i < 90; i++) { - gfxConvertSpriteToRaw(textTable[i][0], tempBuffer, 8, 8); - generateMask(textTable[i][0], textTable[i][1], 8 * 8, 0); + gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 8, 8); + generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 8 * 8, 0); tempBuffer += 0x40; } } diff --git a/engines/cine/texte.h b/engines/cine/texte.h index ae82832aea..f471c3c49e 100644 --- a/engines/cine/texte.h +++ b/engines/cine/texte.h @@ -34,7 +34,10 @@ namespace Cine { typedef char CommandeType[20]; extern byte *textDataPtr; -extern byte textTable[256][2][16 * 8]; + +struct TextHandler { + byte textTable[256][2][16 * 8]; +}; extern const char **failureMessages; extern const CommandeType *defaultActionCommand; diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 46168b306c..b70201ce99 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -464,17 +464,26 @@ bool CineEngine::makeLoad(char *saveName) { broken = brokenSave(*fHandle); + // At savefile position 0x0000: currentDisk = fHandle->readUint16BE(); + // At 0x0002: fHandle->read(currentPartName, 13); + // At 0x000F: fHandle->read(currentDatName, 13); + // At 0x001C: saveVar2 = fHandle->readSint16BE(); + // At 0x001E: fHandle->read(currentPrcName, 13); + // At 0x002B: fHandle->read(currentRelName, 13); + // At 0x0038: fHandle->read(currentMsgName, 13); + // At 0x0045: fHandle->read(bgName, 13); + // At 0x0052: fHandle->read(currentCtName, 13); checkDataDisk(currentDisk); @@ -499,52 +508,84 @@ bool CineEngine::makeLoad(char *saveName) { loadCtFW(currentCtName); } + // At 0x005F: fHandle->readUint16BE(); + // At 0x0061: fHandle->readUint16BE(); + // At 0x0063: for (i = 0; i < 255; i++) { + // At 0x0063 + i * 32 + 0: objectTable[i].x = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 2: objectTable[i].y = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 4: objectTable[i].mask = fHandle->readUint16BE(); + // At 0x0063 + i * 32 + 6: objectTable[i].frame = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 8: objectTable[i].costume = fHandle->readSint16BE(); + // At 0x0063 + i * 32 + 10: fHandle->read(objectTable[i].name, 20); + // At 0x0063 + i * 32 + 30: objectTable[i].part = fHandle->readUint16BE(); } + // At 0x2043 (i.e. 0x0063 + 255 * 32): renderer->restorePalette(*fHandle); + // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): globalVars.load(*fHandle, NUM_MAX_VAR - 1); + // At 0x2281 (i.e. 0x2083 + 255 * 2): for (i = 0; i < 16; i++) { + // At 0x2281 + i * 2: zoneData[i] = fHandle->readUint16BE(); } + // At 0x22A1 (i.e. 0x2281 + 16 * 2): for (i = 0; i < 4; i++) { + // At 0x22A1 + i * 2: commandVar3[i] = fHandle->readUint16BE(); } + // At 0x22A9 (i.e. 0x22A1 + 4 * 2): fHandle->read(commandBuffer, 0x50); renderer->setCommand(commandBuffer); + // At 0x22F9 (i.e. 0x22A9 + 0x50): renderer->_cmdY = fHandle->readUint16BE(); + // At 0x22FB: bgVar0 = fHandle->readUint16BE(); + // At 0x22FD: allowPlayerInput = fHandle->readUint16BE(); + // At 0x22FF: playerCommand = fHandle->readSint16BE(); + // At 0x2301: commandVar1 = fHandle->readSint16BE(); + // At 0x2303: isDrawCommandEnabled = fHandle->readUint16BE(); + // At 0x2305: var5 = fHandle->readUint16BE(); + // At 0x2307: var4 = fHandle->readUint16BE(); + // At 0x2309: var3 = fHandle->readUint16BE(); + // At 0x230B: var2 = fHandle->readUint16BE(); + // At 0x230D: commandVar2 = fHandle->readSint16BE(); + // At 0x230F: renderer->_messageBg = fHandle->readUint16BE(); + // At 0x2311: fHandle->readUint16BE(); + // At 0x2313: fHandle->readUint16BE(); + // At 0x2315: loadResourcesFromSave(*fHandle, broken); // TODO: handle screen params (really required ?) @@ -1516,12 +1557,22 @@ void mainLoopSub6(void) { void checkForPendingDataLoad(void) { if (newPrcName[0] != 0) { - loadPrc(newPrcName); + bool loadPrcOk = loadPrc(newPrcName); strcpy(currentPrcName, newPrcName); strcpy(newPrcName, ""); - addScriptToList0(1); + // Check that the loading of the script file was successful before + // trying to add script 1 from it to the global scripts list. This + // fixes a crash when failing copy protection in Amiga or Atari ST + // versions of Future Wars. + if (loadPrcOk) { + addScriptToList0(1); + } else if (scumm_stricmp(currentPrcName, COPY_PROT_FAIL_PRC_NAME)) { + // We only show an error here for other files than the file that + // is loaded if copy protection fails (i.e. L201.ANI). + warning("checkForPendingDataLoad: loadPrc(%s) failed", currentPrcName); + } } if (newRelName[0] != 0) { diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index cc97f43a05..6121f6979c 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -112,7 +112,7 @@ int KyraEngine_v1::init() { _sound = new SoundTownsPC98_v2(this, _mixer); } else if (_flags.platform == Common::kPlatformPC98) { if (_flags.gameID == GI_KYRA1) - _sound = new SoundPC98(this, _mixer); + _sound = new SoundTowns/*SoundPC98*/(this, _mixer); else _sound = new SoundTownsPC98_v2(this, _mixer); } else if (midiDriver == MD_ADLIB) { diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index e96cef735c..0f2b916c9d 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -2363,7 +2363,7 @@ TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { setTempo(84); - _baserate = (3579545.0 / (double)getRate()) / 144.0; + _baserate = (double)getRate() / 10368.0; } TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { @@ -3095,8 +3095,8 @@ SoundTownsPC98_v2::~SoundTownsPC98_v2() { } bool SoundTownsPC98_v2::init() { - _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? - TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); + _driver = new TownsPC98_OpnDriver(_mixer, /*_vm->gameFlags().platform == Common::kPlatformPC98 ? + TownsPC98_OpnDriver::OD_TYPE86 :*/ TownsPC98_OpnDriver::OD_TOWNS); _useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false; _vm->checkCD(); // FIXME: While checking for 'track1.XXX(X)' looks like diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 4f577c1d1e..c05795dacd 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1034,8 +1034,10 @@ void KyraEngine_LoK::initStaticResource() { } // audio data tables +#if 0 static const char *tIntro98[] = { "intro%d.dat" }; static const char *tIngame98[] = { "kyram%d.dat" }; +#endif static const AudioDataStruct soundData_PC[] = { { _soundFilesIntro, _soundFilesIntroSize, 0, 0 }, @@ -1049,18 +1051,20 @@ void KyraEngine_LoK::initStaticResource() { { 0, 0, 0, 0} }; +#if 0 static const AudioDataStruct soundData_PC98[] = { { tIntro98, 1, 0, 0 }, { tIngame98, 1, 0, 0 }, { 0, 0, 0, 0} }; +#endif if (_flags.platform == Common::kPlatformPC) _soundData = soundData_PC; else if (_flags.platform == Common::kPlatformFMTowns) _soundData = soundData_TOWNS; else if (_flags.platform == Common::kPlatformPC98) - _soundData = soundData_PC98; + _soundData = soundData_TOWNS/*soundData_PC98*/; } @@ -1259,9 +1263,11 @@ void KyraEngine_HoF::initStaticResource() { static const char *fmtMusicFileListFinale[] = { "finale%d.twn" }; static const char *fmtMusicFileListIngame[] = { "km%02d.twn" }; +#if 0 static const char *pc98MusicFileListIntro[] = { "intro%d.86" }; static const char *pc98MusicFileListFinale[] = { "finale%d.86" }; static const char *pc98MusicFileListIngame[] = { "km%02d.86" }; +#endif static const AudioDataStruct soundData_PC[] = { { _musicFileListIntro, _musicFileListIntroSize, 0, 0 }, @@ -1275,18 +1281,20 @@ void KyraEngine_HoF::initStaticResource() { { fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 } }; +#if 0 static const AudioDataStruct soundData_PC98[] = { { pc98MusicFileListIntro, 1, 0, 0 }, { pc98MusicFileListIngame, 1, 0, 0 }, { pc98MusicFileListFinale, 1, 0, 0 } }; +#endif if (_flags.platform == Common::kPlatformPC) _soundData = soundData_PC; else if (_flags.platform == Common::kPlatformFMTowns) _soundData = soundData_TOWNS; else if (_flags.platform == Common::kPlatformPC98) - _soundData = soundData_PC98; + _soundData = soundData_TOWNS/*soundData_PC98*/; // setup sequence data _sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize); diff --git a/engines/lure/luredefs.h b/engines/lure/luredefs.h index 603102a099..922e1207d0 100644 --- a/engines/lure/luredefs.h +++ b/engines/lure/luredefs.h @@ -36,7 +36,7 @@ namespace Lure { #define LURE_DAT_MAJOR 1 #define LURE_DAT_MINOR 29 #define LURE_MIN_SAVEGAME_MINOR 25 -#define LURE_SAVEGAME_MINOR 32 +#define LURE_SAVEGAME_MINOR 33 #define LURE_DEBUG 1 diff --git a/engines/lure/res_struct.cpp b/engines/lure/res_struct.cpp index de09f982d1..92cea948f9 100644 --- a/engines/lure/res_struct.cpp +++ b/engines/lure/res_struct.cpp @@ -456,6 +456,8 @@ void HotspotData::saveToStream(WriteStream *stream) { stream->writeSint16LE(startY); stream->writeUint16LE(roomNumber); stream->writeByte(layer); + stream->writeUint16LE(walkX); + stream->writeUint16LE(walkY); stream->writeUint16LE(width); stream->writeUint16LE(height); @@ -503,6 +505,10 @@ void HotspotData::loadFromStream(ReadStream *stream) { uint8 saveVersion = LureEngine::getReference().saveVersion(); if (saveVersion >= 29) layer = stream->readByte(); + if (saveVersion >= 33) { + walkX = stream->readUint16LE(); + walkY = stream->readUint16LE(); + } width = stream->readUint16LE(); height = stream->readUint16LE(); diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 7c053715f6..ed60a193ce 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -424,6 +424,7 @@ void Parallaction_ns::_c_testResult(void *parm) { } _inTestResult = true; + _gfx->freeLabels(); _gfx->updateScreen(); _disk->selectArchive("disk1"); diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index a771f960a9..96491bf084 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -42,13 +42,23 @@ namespace Parallaction { #define ANSWER_CHARACTER_X 10 #define ANSWER_CHARACTER_Y 80 + class DialogueManager { + enum { + RUN_QUESTION, + RUN_ANSWER, + NEXT_QUESTION, + NEXT_ANSWER, + DIALOGUE_OVER + } _state; + Parallaction *_vm; - SpeakData *_data; Dialogue *_dialogue; bool _askPassword; + int _passwordLen; + bool _passwordChanged; bool isNpc; GfxObj *_questioner; @@ -59,93 +69,70 @@ class DialogueManager { uint16 _visAnswers[5]; int _numVisAnswers; + int _answerId; + + int _selection, _oldSelection; + + uint32 _mouseButtons; + Common::Point _mousePos; + bool _isKeyDown; + uint16 _downKey; + + public: - DialogueManager(Parallaction *vm, SpeakData *data) : _vm(vm), _data(data) { - _dialogue = _data->_dialogue; - isNpc = scumm_stricmp(_data->_name, "yourself") && _data->_name[0] != '\0'; - _questioner = isNpc ? _vm->_disk->loadTalk(_data->_name) : _vm->_char._talk; - _answerer = _vm->_char._talk; - } + DialogueManager(Parallaction *vm, ZonePtr z); + ~DialogueManager(); - ~DialogueManager() { - if (isNpc) { - delete _questioner; - } + bool isOver() { + return _state == DIALOGUE_OVER; } - void run(); + ZonePtr _z; + CommandList *_cmdList; + protected: - void displayQuestion(); + bool displayQuestion(); bool displayAnswers(); bool displayAnswer(uint16 i); - uint16 getAnswer(); - int16 selectAnswer(); - uint16 askPassword(); + int16 selectAnswer1(); + int16 selectAnswerN(); + int16 askPassword(); int16 getHoverAnswer(int16 x, int16 y); -}; - -uint16 DialogueManager::askPassword() { - debugC(3, kDebugExec, "checkDialoguePassword()"); + void runQuestion(); + void runAnswer(); + void nextQuestion(); + void nextAnswer(); - uint16 passwordLen = 0; - _password[0] = '\0'; - - _vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); - int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); - _vm->_gfx->setItemFrame(id, 0); - - Common::Event e; - bool changed = true; // force first refresh - - while (true) { - e.kbd.ascii = 0; - - if (g_system->getEventManager()->pollEvent(e)) { - if ((e.type == Common::EVENT_KEYDOWN) && isdigit(e.kbd.ascii)) { - _password[passwordLen] = e.kbd.ascii; - passwordLen++; - _password[passwordLen] = '\0'; - changed = true; - } - } - - if (changed) { - _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3); - _vm->_gfx->updateScreen(); - changed = false; - } - - if ((passwordLen == MAX_PASSWORD_LENGTH) || (e.kbd.ascii == Common::KEYCODE_RETURN)) { - - if ((!scumm_stricmp(_vm->_char.getBaseName(), _doughName) && !scumm_strnicmp(_password, "1732461", 7)) || - (!scumm_stricmp(_vm->_char.getBaseName(), _donnaName) && !scumm_strnicmp(_password, "1622", 4)) || - (!scumm_stricmp(_vm->_char.getBaseName(), _dinoName) && !scumm_strnicmp(_password, "179", 3))) { + bool checkPassword(); + void resetPassword(); + void accumPassword(uint16 ascii); +}; - break; +DialogueManager::DialogueManager(Parallaction *vm, ZonePtr z) : _vm(vm), _z(z) { + _dialogue = _z->u.speak->_dialogue; + isNpc = scumm_stricmp(_z->u.speak->_name, "yourself") && _z->u.speak->_name[0] != '\0'; + _questioner = isNpc ? _vm->_disk->loadTalk(_z->u.speak->_name) : _vm->_char._talk; + _answerer = _vm->_char._talk; - } else { - passwordLen = 0; - _password[0] = '\0'; - changed = true; - } + _askPassword = false; + _q = _dialogue->_questions[0]; - } + _cmdList = 0; + _answerId = 0; - g_system->delayMillis(20); + _state = displayQuestion() ? RUN_QUESTION : NEXT_ANSWER; +} +DialogueManager::~DialogueManager() { + if (isNpc) { + delete _questioner; } - - _vm->hideDialogueStuff(); - - return 0; - + _z = nullZonePtr; } - - bool DialogueManager::displayAnswer(uint16 i) { Answer *a = _q->_answers[i]; @@ -161,7 +148,7 @@ bool DialogueManager::displayAnswer(uint16 i) { assert(id >= 0); _visAnswers[id] = i; - _askPassword = (strstr(a->_text, "%p") != NULL); + _askPassword = (strstr(a->_text, "%P") != NULL); _numVisAnswers++; return true; @@ -178,134 +165,244 @@ bool DialogueManager::displayAnswers() { displayAnswer(i); } + if (_askPassword) { + resetPassword(); +// _vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3); + int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + _vm->_gfx->setItemFrame(id, 0); + } else + if (_numVisAnswers == 1) { + int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); + _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, 0); + } else + if (_numVisAnswers > 1) { + int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); + _vm->_gfx->setItemFrame(id, _q->_answers[_visAnswers[0]]->_mood & 0xF); + _oldSelection = -1; + _selection = 0; + } + return _numVisAnswers > 0; } -void DialogueManager::displayQuestion() { - - if (!scumm_stricmp(_q->_text, "NULL")) return; +bool DialogueManager::displayQuestion() { + if (!scumm_stricmp(_q->_text, "NULL")) return false; _vm->_balloonMan->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0); int id = _vm->_gfx->setItem(_questioner, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y); _vm->_gfx->setItemFrame(id, _q->_mood & 0xF); - _vm->_gfx->updateScreen(); - _vm->_input->waitUntilLeftClick(); - _vm->hideDialogueStuff(); + return true; +} - return; + +bool DialogueManager::checkPassword() { + return ((!scumm_stricmp(_vm->_char.getBaseName(), _doughName) && !scumm_strnicmp(_password, "1732461", 7)) || + (!scumm_stricmp(_vm->_char.getBaseName(), _donnaName) && !scumm_strnicmp(_password, "1622", 4)) || + (!scumm_stricmp(_vm->_char.getBaseName(), _dinoName) && !scumm_strnicmp(_password, "179", 3))); } -uint16 DialogueManager::getAnswer() { +void DialogueManager::resetPassword() { + _passwordLen = 0; + _password[0] = '\0'; + _passwordChanged = true; +} - uint16 answer = 0; +void DialogueManager::accumPassword(uint16 ascii) { + if (!isdigit(ascii)) { + return; + } - if (_askPassword == false) { - answer = selectAnswer(); - } else { - answer = askPassword(); + _password[_passwordLen] = ascii; + _passwordLen++; + _password[_passwordLen] = '\0'; + _passwordChanged = true; +} + +int16 DialogueManager::askPassword() { + + if (_isKeyDown) { + accumPassword(_downKey); + } + + if (_passwordChanged) { + _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3); + _passwordChanged = false; } - debugC(3, kDebugExec, "runDialogue: user selected answer #%i", answer); + if ((_passwordLen == MAX_PASSWORD_LENGTH) || ((_isKeyDown) && (_downKey == Common::KEYCODE_RETURN))) { + if (checkPassword()) { + return 0; + } else { + resetPassword(); + } + } - return answer; + return -1; } -void DialogueManager::run() { +int16 DialogueManager::selectAnswer1() { - _askPassword = false; - CommandList *cmdlist = NULL; + if (_mouseButtons == kMouseLeftUp) { + return 0; + } - _q = _dialogue->_questions[0]; - int16 answer; + return -1; +} - while (_q) { +int16 DialogueManager::selectAnswerN() { - answer = 0; + _selection = _vm->_balloonMan->hitTestDialogueBalloon(_mousePos.x, _mousePos.y); - displayQuestion(); + if (_selection != _oldSelection) { + if (_oldSelection != -1) { + _vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, 3); + } if (_vm->quit()) - return; + return -1; + + if (_selection != -1) { + _vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, 0); + _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[_selection]]->_mood & 0xF); + } + } - if (_q->_answers[0] == NULL) break; + _oldSelection = _selection; - if (scumm_stricmp(_q->_answers[0]->_text, "NULL")) { - if (!displayAnswers()) break; - answer = getAnswer(); + if ((_mouseButtons == kMouseLeftUp) && (_selection != -1)) { + return _visAnswers[_selection]; + } - if (_vm->quit()) - return; + return -1; +} - cmdlist = &_q->_answers[answer]->_commands; - } +void DialogueManager::runQuestion() { + debugC(9, kDebugDialogue, "runQuestion\n"); - _q = _q->_answers[answer]->_following._question; + if (_mouseButtons == kMouseLeftUp) { + _vm->hideDialogueStuff(); + _state = NEXT_ANSWER; } - if (cmdlist) - _vm->_cmdExec->run(*cmdlist); - } -int16 DialogueManager::selectAnswer() { - int16 numAvailableAnswers = _numVisAnswers; +void DialogueManager::nextAnswer() { + debugC(9, kDebugDialogue, "nextAnswer\n"); + + if (_q->_answers[0] == NULL) { + _state = DIALOGUE_OVER; + return; + } + + if (!scumm_stricmp(_q->_answers[0]->_text, "NULL")) { + _answerId = 0; + _state = NEXT_QUESTION; + return; + } - int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y); - _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); + _state = displayAnswers() ? RUN_ANSWER : DIALOGUE_OVER; +} + +void DialogueManager::runAnswer() { + debugC(9, kDebugDialogue, "runAnswer\n"); - if (numAvailableAnswers == 1) { - _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 0); - _vm->_input->waitUntilLeftClick(); + if (_askPassword) { + _answerId = askPassword(); + } else + if (_numVisAnswers == 1) { + _answerId = selectAnswer1(); + } else { + _answerId = selectAnswerN(); + } + + if (_answerId != -1) { + _cmdList = &_q->_answers[_answerId]->_commands; _vm->hideDialogueStuff(); - return 0; + _state = NEXT_QUESTION; } +} - int oldSelection = -1; - int selection = 0; - - uint32 event; - Common::Point p; - while (!_vm->quit()) { - - _vm->_input->readInput(); - _vm->_input->getCursorPos(p); - event = _vm->_input->getLastButtonEvent(); - selection = _vm->_balloonMan->hitTestDialogueBalloon(p.x, p.y); - - if (selection != oldSelection) { - if (oldSelection != -1) { - _vm->_balloonMan->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3); - } - - if (selection != -1) { - _vm->_balloonMan->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0); - _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[selection]]->_mood & 0xF); - } - } +void DialogueManager::nextQuestion() { + debugC(9, kDebugDialogue, "nextQuestion\n"); + + _q = _q->_answers[_answerId]->_following._question; + if (_q == 0) { + _state = DIALOGUE_OVER; + } else { + _state = displayQuestion() ? RUN_QUESTION : NEXT_ANSWER; + } +} + +void DialogueManager::run() { + + // cache event data + _mouseButtons = _vm->_input->getLastButtonEvent(); + _vm->_input->getCursorPos(_mousePos); + _isKeyDown = _vm->_input->getLastKeyDown(_downKey); - if ((selection != -1) && (event == kMouseLeftUp)) { - break; + switch (_state) { + case RUN_QUESTION: + runQuestion(); + break; + + case NEXT_ANSWER: + nextAnswer(); + break; + + case NEXT_QUESTION: + nextQuestion(); + break; + + case RUN_ANSWER: + runAnswer(); + break; + + case DIALOGUE_OVER: + if (_cmdList) { + _vm->_cmdExec->run(*_cmdList); } + break; - _vm->_gfx->updateScreen(); - g_system->delayMillis(20); + default: + error("unknown state in DialogueManager"); - oldSelection = selection; } - _vm->hideDialogueStuff(); +} - return _visAnswers[selection]; +void Parallaction::enterDialogueMode(ZonePtr z) { + debugC(1, kDebugDialogue, "Parallaction::enterDialogueMode(%s)", z->u.speak->_name); + _dialogueMan = new DialogueManager(this, z); + _input->_inputMode = Input::kInputModeDialogue; } +void Parallaction::exitDialogueMode() { + debugC(1, kDebugDialogue, "Parallaction::exitDialogueMode()"); + _input->_inputMode = Input::kInputModeGame; -void Parallaction::runDialogue(SpeakData *data) { - debugC(1, kDebugExec, "runDialogue: starting dialogue '%s'", data->_name); + // The current instance of _dialogueMan must be destroyed before the zone commands + // are executed, because they may create another instance of _dialogueMan that + // overwrite the current one. This would cause headaches (and it did, actually). + ZonePtr z = _dialogueMan->_z; + delete _dialogueMan; + _dialogueMan = 0; - DialogueManager man(this, data); - man.run(); + _cmdExec->run(z->_commands, z); +} + +void Parallaction::runDialogueFrame() { + if (_input->_inputMode != Input::kInputModeDialogue) { + return; + } + + _dialogueMan->run(); + + if (_dialogueMan->isOver()) { + exitDialogueMode(); + } return; } diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index c77c70cd6e..913e7ae648 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -224,7 +224,11 @@ DECLARE_COMMAND_OPCODE(start) { DECLARE_COMMAND_OPCODE(speak) { - _vm->_activeZone = _ctxt.cmd->u._zone; + if ((_ctxt.cmd->u._zone->_type & 0xFFFF) == kZoneSpeak) { + _vm->enterDialogueMode(_ctxt.cmd->u._zone); + } else { + _vm->_activeZone = _ctxt.cmd->u._zone; + } } @@ -322,6 +326,7 @@ DECLARE_COMMAND_OPCODE(stop) { void Parallaction_ns::drawAnimations() { + debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n"); uint16 layer = 0; @@ -362,6 +367,8 @@ void Parallaction_ns::drawAnimations() { } } + debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n"); + return; } @@ -417,7 +424,6 @@ label1: return; } - void CommandExec::run(CommandList& list, ZonePtr z) { if (list.size() == 0) { debugC(3, kDebugExec, "runCommands: nothing to do"); @@ -542,11 +548,8 @@ uint16 Parallaction::runZone(ZonePtr z) { break; case kZoneSpeak: - runDialogue(z->u.speak); - if (_vm->quit()) - return 0; - break; - + enterDialogueMode(z); + return 0; } debugC(3, kDebugExec, "runZone completed"); diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 9e7eb12ed8..e8250ac8fd 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -267,9 +267,6 @@ void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte } -// this is the maximum size of an unpacked frame in BRA -byte _unpackedBitmap[640*401]; - #if 0 void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 32d0e303eb..9b9ea8605a 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -33,6 +33,11 @@ namespace Parallaction { +// this is the size of the receiving buffer for unpacked frames, +// since BRA uses some insanely big animations. +#define MAXIMUM_UNPACKED_BITMAP_SIZE 640*401 + + void Gfx::registerVar(const Common::String &name, int32 initialValue) { if (_vars.contains(name)) { warning("Variable '%s' already registered, ignoring initial value.\n", name.c_str()); @@ -752,6 +757,9 @@ Gfx::Gfx(Parallaction* vm) : _halfbrite = false; _hbCircleRadius = 0; + _unpackedBitmap = new byte[MAXIMUM_UNPACKED_BITMAP_SIZE]; + assert(_unpackedBitmap); + registerVar("background_mode", 1); _varBackgroundMode = 1; @@ -769,6 +777,8 @@ Gfx::~Gfx() { freeBackground(); freeLabels(); + delete []_unpackedBitmap; + return; } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 09f4b2f244..a7242ba6f4 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -547,6 +547,8 @@ public: uint _screenX; // scrolling position uint _screenY; + byte *_unpackedBitmap; + protected: Parallaction* _vm; bool _halfbrite; diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index e57b95678f..d625199e2b 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -42,12 +42,14 @@ uint16 Input::readInput() { uint16 KeyDown = 0; _mouseButtons = kMouseNone; + _lastKeyDownAscii = -1; Common::EventManager *eventMan = _vm->_system->getEventManager(); while (eventMan->pollEvent(e)) { switch (e.type) { case Common::EVENT_KEYDOWN: + _lastKeyDownAscii = e.kbd.ascii; if (e.kbd.flags == Common::KBD_CTRL && e.kbd.keycode == 'd') _vm->_debugger->attach(); if (_vm->getFeatures() & GF_DEMO) break; @@ -97,6 +99,11 @@ uint16 Input::readInput() { } +bool Input::getLastKeyDown(uint16 &ascii) { + ascii = _lastKeyDownAscii; + return (_lastKeyDownAscii != -1); +} + // FIXME: see comment for readInput() void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) { @@ -192,11 +199,38 @@ InputData* Input::updateInput() { case kInputModeGame: updateGameInput(); break; + + case kInputModeDialogue: + readInput(); + break; } return &_inputData; } +void Input::trackMouse(ZonePtr z) { + if ((z != _hoverZone) && (_hoverZone)) { + stopHovering(); + return; + } + + if (!z) { + return; + } + + if ((!_hoverZone) && ((z->_flags & kFlagsNoName) == 0)) { + _hoverZone = z; + _vm->_gfx->showFloatingLabel(_hoverZone->_label); + return; + } +} + +void Input::stopHovering() { + _hoverZone = nullZonePtr; + _vm->_gfx->hideFloatingLabel(); +} + + bool Input::translateGameInput() { if ((_engineFlags & kEnginePauseJobs) || (_engineFlags & kEngineInventory)) { @@ -231,23 +265,10 @@ bool Input::translateGameInput() { return true; } - if ((z != _hoverZone) && (_hoverZone)) { - _hoverZone = nullZonePtr; - _inputData._event = kEvExitZone; - return true; - } - - if (!z) { - _inputData._event = kEvNone; - return true; - } - - if ((!_hoverZone) && ((z->_flags & kFlagsNoName) == 0)) { - _hoverZone = z; - _inputData._event = kEvEnterZone; - _inputData._label = z->_label; - return true; - } + trackMouse(z); + if (!z) { + return true; + } if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) { diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index e06fe96705..f260352dba 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -66,6 +66,7 @@ class Input { Common::Point _mousePos; uint16 _mouseButtons; + int32 _lastKeyDownAscii; bool _mouseHidden; ZonePtr _hoverZone; @@ -73,7 +74,8 @@ class Input { public: enum { kInputModeGame = 0, - kInputModeComment = 1 + kInputModeComment = 1, + kInputModeDialogue = 2 }; @@ -99,14 +101,13 @@ public: uint16 readInput(); InputData* updateInput(); + void trackMouse(ZonePtr z); void waitUntilLeftClick(); void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1); uint32 getLastButtonEvent() { return _mouseButtons; } + bool getLastKeyDown(uint16 &ascii); - void stopHovering() { - _hoverZone = nullZonePtr; - } - + void stopHovering(); }; } // namespace Parallaction diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index c998e26024..fff50b48df 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -164,6 +164,11 @@ void Parallaction::updateView() { } +void Parallaction::hideDialogueStuff() { + _gfx->freeItems(); + _balloonMan->freeBalloons(); +} + void Parallaction::freeCharacter() { debugC(1, kDebugExec, "freeCharacter()"); @@ -297,16 +302,6 @@ void Parallaction::showLocationComment(const char *text, bool end) { void Parallaction::processInput(InputData *data) { switch (data->_event) { - case kEvEnterZone: - debugC(2, kDebugInput, "processInput: kEvEnterZone"); - _gfx->showFloatingLabel(data->_label); - break; - - case kEvExitZone: - debugC(2, kDebugInput, "processInput: kEvExitZone"); - _gfx->hideFloatingLabel(); - break; - case kEvAction: debugC(2, kDebugInput, "processInput: kEvAction"); _input->stopHovering(); @@ -317,7 +312,6 @@ void Parallaction::processInput(InputData *data) { case kEvOpenInventory: _input->stopHovering(); - _gfx->hideFloatingLabel(); if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) { setArrowCursor(); } @@ -367,25 +361,29 @@ void Parallaction::processInput(InputData *data) { void Parallaction::runGame() { InputData *data = _input->updateInput(); - if (data->_event != kEvNone) { - processInput(data); - } - if (_vm->quit()) return; - runPendingZones(); + if (_input->_inputMode == Input::kInputModeDialogue) { + runDialogueFrame(); + } else { + if (data->_event != kEvNone) { + processInput(data); + } - if (_vm->quit()) - return; + if (_vm->quit()) + return; - if (_engineFlags & kEngineChangeLocation) { - changeLocation(_location._name); - } + runPendingZones(); if (_vm->quit()) return; + if (_engineFlags & kEngineChangeLocation) { + changeLocation(_location._name); + } + } + _gfx->beginFrame(); if (_input->_inputMode == Input::kInputModeGame) { @@ -400,7 +398,6 @@ void Parallaction::runGame() { // change this to endFrame? updateView(); - } @@ -668,6 +665,7 @@ void Parallaction::beep() { } void Parallaction::scheduleLocationSwitch(const char *location) { + debugC(9, kDebugExec, "scheduleLocationSwitch(%s)\n", location); strcpy(_location._name, location); _engineFlags |= kEngineChangeLocation; } diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index a90f8c4f48..115099addd 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -113,8 +113,6 @@ enum EngineFlags { enum { kEvNone = 0, - kEvEnterZone = 1, - kEvExitZone = 2, kEvAction = 3, kEvOpenInventory = 4, kEvCloseInventory = 5, @@ -164,6 +162,7 @@ class Debugger; class Gfx; class SoundMan; class Input; +class DialogueManager; struct Location { @@ -281,8 +280,6 @@ public: uint16 runZone(ZonePtr z); void freeZones(); - void runDialogue(SpeakData*); - AnimationPtr findAnimation(const char *name); void freeAnimations(); @@ -425,10 +422,11 @@ public: void setupBalloonManager(); - void hideDialogueStuff() { - _gfx->freeItems(); - _balloonMan->freeBalloons(); - } + void hideDialogueStuff(); + DialogueManager *_dialogueMan; + void enterDialogueMode(ZonePtr z); + void exitDialogueMode(); + void runDialogueFrame(); }; diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 090184e9fe..0c8058e4bd 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -212,13 +212,21 @@ void Parallaction_br::runPendingZones() { if (_activeZone) { z = _activeZone; // speak Zone or sound _activeZone = nullZonePtr; - runZone(z); // FIXME: BRA doesn't handle sound yet + if ((z->_type & 0xFFFF) == kZoneSpeak) { + enterDialogueMode(z); + } else { + runZone(z); // FIXME: BRA doesn't handle sound yet + } } if (_activeZone2) { z = _activeZone2; // speak Zone or sound _activeZone2 = nullZonePtr; - runZone(z); + if ((z->_type & 0xFFFF) == kZoneSpeak) { + enterDialogueMode(z); + } else { + runZone(z); // FIXME: BRA doesn't handle sound yet + } } } diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index e5baf1864d..e8264238a1 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -191,7 +191,7 @@ void Parallaction_ns::setArrowCursor() { debugC(1, kDebugInput, "setting mouse cursor to arrow"); // this stuff is needed to avoid artifacts with labels and selected items when switching cursors - _gfx->hideFloatingLabel(); + _input->stopHovering(); _input->_activeItem._id = 0; _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); @@ -302,12 +302,11 @@ void Parallaction_ns::changeLocation(char *location) { _soundMan->playLocationMusic(location); - _gfx->hideFloatingLabel(); + _input->stopHovering(); _gfx->freeLabels(); _zoneTrap = nullZonePtr; - _input->stopHovering(); if (_engineFlags & kEngineBlockInput) { setArrowCursor(); } @@ -420,6 +419,7 @@ void Parallaction_ns::changeCharacter(const char *name) { Common::String oldArchive = _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1"); _char._ani->gfxobj = _gfx->loadAnim(_char.getFullName()); _char._ani->gfxobj->setFlags(kGfxObjCharacter); + _char._ani->gfxobj->clearFlags(kGfxObjNormal); if (!_char.dummy()) { if (getPlatform() == Common::kPlatformAmiga) { diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 40dfddb903..a717b615e6 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -354,6 +354,7 @@ void Parallaction_ns::walk(Character &character) { if (newPos == curPos) { debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle"); finalizeWalk(character); + targetPos = newPos; // when walking is interrupted, targetPos must be hacked so that a still frame can be selected } } diff --git a/engines/queen/graphics.cpp b/engines/queen/graphics.cpp index f863f7663c..6d0a11ccfe 100644 --- a/engines/queen/graphics.cpp +++ b/engines/queen/graphics.cpp @@ -1175,15 +1175,8 @@ BamScene::BamScene(QueenEngine *vm) } void BamScene::playSfx() { - // Don't try to play all the sounds. This is only necessary for the - // fight bam, in which the number of 'sfx bam frames' is too much - // important / too much closer. The original game does not have - // this problem since its playSfx() function returns immediately - // if a sound is already being played. - if (_lastSoundIndex == 0 || _index - _lastSoundIndex >= SFX_SKIP) { - _vm->sound()->playSfx(_vm->logic()->currentRoomSfx()); - _lastSoundIndex = _index; - } + _vm->sound()->playSfx(_vm->logic()->currentRoomSfx()); + _lastSoundIndex = _index; } void BamScene::prepareAnimation() { diff --git a/engines/queen/graphics.h b/engines/queen/graphics.h index 6f00111635..7eadf9a191 100644 --- a/engines/queen/graphics.h +++ b/engines/queen/graphics.h @@ -248,10 +248,6 @@ public: F_REQ_STOP = 2 }; - enum { - SFX_SKIP = 8 - }; - uint16 _flag, _index; private: diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp index d17a73c90b..9cdd971857 100644 --- a/engines/queen/sound.cpp +++ b/engines/queen/sound.cpp @@ -227,11 +227,6 @@ void PCSound::setVolume(int vol) { _music->setVolume(vol); } -void PCSound::waitFinished(bool isSpeech) { - while (_mixer->isSoundHandleActive(isSpeech ? _speechHandle : _sfxHandle)) - _vm->input()->delay(10); -} - void PCSound::playSound(const char *base, bool isSpeech) { char name[13]; strcpy(name, base); @@ -241,7 +236,13 @@ void PCSound::playSound(const char *base, bool isSpeech) { name[i] = '0'; } strcat(name, ".SB"); - waitFinished(isSpeech); + if (isSpeech) { + while (_mixer->isSoundHandleActive(_speechHandle)) { + _vm->input()->delay(10); + } + } else { + _mixer->stopHandle(_sfxHandle); + } uint32 size; Common::File *f = _vm->resource()->findSound(name, &size); if (f) { @@ -253,6 +254,8 @@ void PCSound::playSound(const char *base, bool isSpeech) { } void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) { + // In order to simplify the code, we don't parse the .sb header but hard-code the + // values. Refer to tracker item #1876741 for details on the format/fields. int headerSize; f->seek(2, SEEK_CUR); uint16 version = f->readUint16LE(); diff --git a/engines/queen/sound.h b/engines/queen/sound.h index c2c1481cc6..331034f746 100644 --- a/engines/queen/sound.h +++ b/engines/queen/sound.h @@ -143,7 +143,6 @@ public: void setVolume(int vol); protected: - void waitFinished(bool isSpeech); void playSound(const char *base, bool isSpeech); virtual void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) = 0; diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 753ad45212..68d3010199 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -949,7 +949,7 @@ SaveStateList ScummMetaEngine::listSaves(const char *target) const { sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; - for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++) { + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { // Obtain the last 2 digits of the filename, since they correspond to the save slot int slotNum = atoi(file->c_str() + file->size() - 2); diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 310cfc50a6..cb9113fe65 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -297,7 +297,7 @@ void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 da break; case GUI::kListSelectionChangedCmd: { if (_gfxWidget) { - updateInfos(); + updateInfos(true); } if (_saveMode) { @@ -350,7 +350,7 @@ void SaveLoadChooser::reflowLayout() { _fillR = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillR"); _fillG = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillG"); _fillB = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillB"); - updateInfos(); + updateInfos(false); } else { _container->setFlags(GUI::WIDGET_INVISIBLE); _gfxWidget->setFlags(GUI::WIDGET_INVISIBLE); @@ -362,7 +362,7 @@ void SaveLoadChooser::reflowLayout() { Dialog::reflowLayout(); } -void SaveLoadChooser::updateInfos() { +void SaveLoadChooser::updateInfos(bool redraw) { int selItem = _list->getSelected(); Graphics::Surface *thumb; thumb = _vm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem); @@ -376,7 +376,8 @@ void SaveLoadChooser::updateInfos() { } delete thumb; - _gfxWidget->draw(); + if (redraw) + _gfxWidget->draw(); InfoStuff infos; memset(&infos, 0, sizeof(InfoStuff)); @@ -386,12 +387,14 @@ void SaveLoadChooser::updateInfos() { (infos.date >> 24) & 0xFF, (infos.date >> 16) & 0xFF, infos.date & 0xFFFF); _date->setLabel(buffer); - _date->draw(); + if (redraw) + _date->draw(); snprintf(buffer, 32, "Time: %.2d:%.2d", (infos.time >> 8) & 0xFF, infos.time & 0xFF); _time->setLabel(buffer); - _time->draw(); + if (redraw) + _time->draw(); int minutes = infos.playtime / 60; int hours = minutes / 60; @@ -400,19 +403,23 @@ void SaveLoadChooser::updateInfos() { snprintf(buffer, 32, "Playtime: %.2d:%.2d", hours & 0xFF, minutes & 0xFF); _playtime->setLabel(buffer); - _playtime->draw(); + if (redraw) + _playtime->draw(); } else { snprintf(buffer, 32, "No date saved"); _date->setLabel(buffer); - _date->draw(); + if (redraw) + _date->draw(); snprintf(buffer, 32, "No time saved"); _time->setLabel(buffer); - _time->draw(); + if (redraw) + _time->draw(); snprintf(buffer, 32, "No playtime saved"); _playtime->setLabel(buffer); - _playtime->draw(); + if (redraw) + _playtime->draw(); } } diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h index 192bb8d0e1..3837787a3b 100644 --- a/engines/scumm/dialogs.h +++ b/engines/scumm/dialogs.h @@ -69,7 +69,7 @@ protected: uint8 _fillR, _fillG, _fillB; - void updateInfos(); + void updateInfos(bool redraw); public: SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode, ScummEngine *engine); ~SaveLoadChooser(); diff --git a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp index 1511b9aefc..b18b0ba70f 100644 --- a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp +++ b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp @@ -102,10 +102,10 @@ void ImuseDigiSndMgr::prepareSoundFromRMAP(Common::File *file, SoundDesc *sound, int32 version = file->readUint32BE(); if (version != 3) { if (version == 2) { - warning("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version of compressed *.bun file, expected 3, but it's 2."); - warning("Suggested to recompress with latest tool from daily builds."); + warning("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version of compressed *.bun file, expected 3, but it's 2"); + warning("Suggested to recompress with latest tool from daily builds"); } else - error("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version number, expected 3, but it's: %d.", version); + error("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version number, expected 3, but it's: %d", version); } sound->bits = file->readUint32BE(); sound->freq = file->readUint32BE(); diff --git a/engines/sword2/music.cpp b/engines/sword2/music.cpp index fd72ba8d52..3b5a09578b 100644 --- a/engines/sword2/music.cpp +++ b/engines/sword2/music.cpp @@ -52,9 +52,11 @@ namespace Sword2 { static Audio::AudioStream *makeCLUStream(Common::File *fp, int size); static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, int cd, uint32 id, uint32 *numSamples) { - debug(3, "Playing %s from CD %d", base, cd); + bool alreadyOpen; if (!fh->file.isOpen()) { + alreadyOpen = false; + struct { const char *ext; int mode; @@ -75,16 +77,14 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, char filename[20]; for (int i = 0; i < ARRAYSIZE(file_types); i++) { - Common::File f; - sprintf(filename, "%s%d.%s", base, cd, file_types[i].ext); - if (f.open(filename)) { + if (Common::File::exists(filename)) { soundMode = file_types[i].mode; break; } sprintf(filename, "%s.%s", base, file_types[i].ext); - if (f.open(filename)) { + if (Common::File::exists(filename)) { soundMode = file_types[i].mode; break; } @@ -105,7 +105,8 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, fh->idxTab = NULL; } } - } + } else + alreadyOpen = true; uint32 entrySize = (fh->fileType == kCLUMode) ? 2 : 3; @@ -134,7 +135,13 @@ static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, *numSamples = len; if (!pos || !len) { - fh->file.close(); + // We couldn't find the sound. Possibly as a result of a bad + // installation (e.g. using the music file from CD 2 as the + // first music file). Don't close the file if it was already + // open though, because something is playing from it. + warning("getAudioStream: Could not find %s ID %d! Possibly the wrong file", base, id); + if (!alreadyOpen) + fh->file.close(); return NULL; } diff --git a/engines/sword2/sound.h b/engines/sword2/sound.h index 70bae6f851..b89ef8f12b 100644 --- a/engines/sword2/sound.h +++ b/engines/sword2/sound.h @@ -106,7 +106,7 @@ private: void refill(); inline bool eosIntern() const { - return _pos >= _bufferEnd; + return !_file->isOpen() || _pos >= _bufferEnd; } public: diff --git a/test/common/str.h b/test/common/str.h index dcba554b5a..76574ea70f 100644 --- a/test/common/str.h +++ b/test/common/str.h @@ -5,16 +5,25 @@ class StringTestSuite : public CxxTest::TestSuite { public: - void test_empty_clear( void ) - { + void test_constructors(void) { + Common::String str("test-string"); + TS_ASSERT( str == "test-string" ); + str = Common::String(str.c_str()+5, 3); + TS_ASSERT( str == "str" ); + str = "test-string"; + TS_ASSERT( str == "test-string" ); + str = Common::String(str.c_str()+5, str.c_str()+8); + TS_ASSERT( str == "str" ); + } + + void test_empty_clear(void) { Common::String str("test"); TS_ASSERT( !str.empty() ); str.clear(); TS_ASSERT( str.empty() ); } - void test_lastChar( void ) - { + void test_lastChar(void) { Common::String str; TS_ASSERT_EQUALS( str.lastChar(), '\0' ); str = "test"; @@ -23,8 +32,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( str2.lastChar(), 'r' ); } - void test_concat1( void ) - { + void test_concat1(void) { Common::String str("foo"); Common::String str2("bar"); str += str2; @@ -32,22 +40,19 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( str2, "bar" ); } - void test_concat2( void ) - { + void test_concat2(void) { Common::String str("foo"); str += "bar"; TS_ASSERT_EQUALS( str, "foobar" ); } - void test_concat3( void ) - { + void test_concat3(void) { Common::String str("foo"); str += 'X'; TS_ASSERT_EQUALS( str, "fooX" ); } - void test_refCount( void ) - { + void test_refCount(void) { Common::String foo1("foo"); Common::String foo2("foo"); Common::String foo3(foo2); @@ -57,8 +62,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( foo3, "foo""X" ); } - void test_refCount2( void ) - { + void test_refCount2(void) { Common::String foo1("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo2("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo3(foo2); @@ -68,8 +72,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""X" ); } - void test_refCount3( void ) - { + void test_refCount3(void) { Common::String foo1("0123456789abcdefghijk"); Common::String foo2("0123456789abcdefghijk"); Common::String foo3(foo2); @@ -79,8 +82,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( foo3, "0123456789abcdefghijk""0123456789abcdefghijk" ); } - void test_refCount4( void ) - { + void test_refCount4(void) { Common::String foo1("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo2("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); Common::String foo3(foo2); @@ -90,8 +92,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd" ); } - void test_hasPrefix( void ) - { + void test_hasPrefix(void) { Common::String str("this/is/a/test, haha"); TS_ASSERT_EQUALS( str.hasPrefix(""), true ); TS_ASSERT_EQUALS( str.hasPrefix("this"), true ); @@ -99,8 +100,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( str.hasPrefix("foo"), false ); } - void test_hasSuffix( void ) - { + void test_hasSuffix(void) { Common::String str("this/is/a/test, haha"); TS_ASSERT_EQUALS( str.hasSuffix(""), true ); TS_ASSERT_EQUALS( str.hasSuffix("haha"), true ); @@ -108,8 +108,7 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( str.hasSuffix("hahah"), false ); } - void test_contains( void ) - { + void test_contains(void) { Common::String str("this/is/a/test, haha"); TS_ASSERT_EQUALS( str.contains(""), true ); TS_ASSERT_EQUALS( str.contains("haha"), true ); @@ -117,15 +116,13 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS( str.contains("test"), true ); } - void test_toLowercase( void ) - { + void test_toLowercase(void) { Common::String str("Test it, NOW! 42"); str.toLowercase(); TS_ASSERT_EQUALS( str, "test it, now! 42" ); } - void test_toUppercase( void ) - { + void test_toUppercase(void) { Common::String str("Test it, NOW! 42"); str.toUppercase(); TS_ASSERT_EQUALS( str, "TEST IT, NOW! 42" ); |