2014-03-15 16:59:03 +00:00
|
|
|
// Emacs style mode select -*- C++ -*-
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/// \file
|
|
|
|
/// \brief cd music interface
|
|
|
|
///
|
|
|
|
|
2014-07-25 23:10:24 +00:00
|
|
|
#ifdef HAVE_SDL
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
#if defined (DC) || defined (_WIN32_WCE) || defined(GP2X) || defined(_PS3)
|
|
|
|
#define NOSDLCD
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#ifndef NOSDLCD
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(disable : 4214 4244)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "SDL.h"
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(default : 4214 4244)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "../doomtype.h"
|
|
|
|
#include "../i_sound.h"
|
|
|
|
#include "../command.h"
|
|
|
|
#include "../m_argv.h"
|
|
|
|
#include "../s_sound.h"
|
|
|
|
|
|
|
|
#define MAX_CD_TRACKS 256
|
|
|
|
|
|
|
|
#ifdef _XBOX
|
|
|
|
INT32 SDL_SYS_CDInit(void)
|
|
|
|
{
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SDL_SYS_CDQuit(void)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
UINT8 cdaudio_started = 0; // for system startup/shutdown
|
|
|
|
|
|
|
|
consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
|
|
|
consvar_t cdUpdate = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
|
|
|
|
|
|
|
|
#ifndef NOSDLCD
|
|
|
|
static SDL_bool cdValid = SDL_FALSE;
|
|
|
|
static SDL_bool cdPlaying = SDL_FALSE;
|
|
|
|
static SDL_bool wasPlaying = SDL_FALSE;
|
|
|
|
static SDL_bool cdEnabled = SDL_FALSE;
|
|
|
|
static SDL_bool playLooping = SDL_FALSE;
|
|
|
|
static Uint8 playTrack = 0;
|
|
|
|
static Uint8 maxTrack = MAX_CD_TRACKS-1;
|
|
|
|
static Uint8 cdRemap[MAX_CD_TRACKS];
|
|
|
|
static INT32 cdvolume = -1;
|
|
|
|
static SDL_CD *cdrom = NULL;
|
|
|
|
static CDstatus cdStatus = CD_ERROR;
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: CDAudio_GetAudioDiskInfo
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
* set number of tracks if CD is available
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
static INT32 CDAudio_GetAudioDiskInfo(void)
|
|
|
|
{
|
|
|
|
cdValid = SDL_FALSE;
|
|
|
|
maxTrack = 0;
|
|
|
|
|
|
|
|
if (!cdrom)
|
|
|
|
return 0;//Alam: Lies!
|
|
|
|
|
|
|
|
cdStatus = SDL_CDStatus(cdrom);
|
|
|
|
|
|
|
|
if (!CD_INDRIVE(cdStatus))
|
|
|
|
{
|
|
|
|
CONS_Printf("%s", M_GetText("No CD in drive\n"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cdStatus == CD_ERROR)
|
|
|
|
{
|
|
|
|
CONS_Printf(M_GetText("CD Error: %s\n"), SDL_GetError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cdValid = SDL_TRUE;
|
|
|
|
maxTrack = (Uint8)cdrom->numtracks;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: I_EjectCD
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
*
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
static void I_EjectCD(void)
|
|
|
|
{
|
|
|
|
if (!cdrom || !cdEnabled)
|
|
|
|
return; // no cd init'd
|
|
|
|
|
|
|
|
I_StopCD();
|
|
|
|
|
|
|
|
if (SDL_CDEject(cdrom))
|
|
|
|
CONS_Printf("%s", M_GetText("CD eject failed\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: Command_Cd_f
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
* handles all CD commands from the console
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
static void Command_Cd_f (void)
|
|
|
|
{
|
|
|
|
const char *command;
|
|
|
|
size_t ret, n;
|
|
|
|
|
|
|
|
if (!cdaudio_started)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (COM_Argc() < 2)
|
|
|
|
{
|
|
|
|
CONS_Printf ("%s", M_GetText("cd [on] [off] [remap] [reset] [select]\n"
|
|
|
|
" [open] [info] [play <track>] [resume]\n"
|
|
|
|
" [stop] [pause] [loop <track>]\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
command = COM_Argv (1);
|
|
|
|
|
|
|
|
if (!strncmp(command, "on", 2))
|
|
|
|
{
|
|
|
|
cdEnabled = SDL_TRUE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(command, "off", 3))
|
|
|
|
{
|
|
|
|
I_StopCD();
|
|
|
|
cdEnabled = SDL_FALSE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(command, "select", 6))
|
|
|
|
{
|
|
|
|
INT32 newcddrive;
|
|
|
|
newcddrive = atoi(COM_Argv(2));
|
|
|
|
command = SDL_CDName(newcddrive);
|
|
|
|
I_StopCD();
|
|
|
|
cdEnabled = SDL_FALSE;
|
|
|
|
SDL_CDClose(cdrom);
|
|
|
|
cdrom = SDL_CDOpen(newcddrive);
|
|
|
|
if (cdrom)
|
|
|
|
{
|
|
|
|
cdEnabled = SDL_TRUE;
|
|
|
|
CONS_Printf(M_GetText("Opened CD-ROM drive %s\n"), command ? command : COM_Argv(2));
|
|
|
|
}
|
|
|
|
else CONS_Printf(M_GetText("Couldn't open CD-ROM drive %s: %s\n"), command ? command : COM_Argv(2), SDL_GetError());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(command, "remap", 5))
|
|
|
|
{
|
|
|
|
ret = COM_Argc() - 2;
|
|
|
|
if (ret <= 0)
|
|
|
|
{
|
|
|
|
for (n = 1; n < MAX_CD_TRACKS; n++)
|
|
|
|
{
|
|
|
|
if (cdRemap[n] != n)
|
|
|
|
CONS_Printf(" %s -> %u\n", sizeu1(n), cdRemap[n]);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (n = 1; n <= ret; n++)
|
|
|
|
cdRemap[n] = (Uint8)atoi(COM_Argv (n+1));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(command, "reset", 5))
|
|
|
|
{
|
|
|
|
if (!cdrom) return;
|
|
|
|
cdEnabled = SDL_TRUE;
|
|
|
|
I_StopCD();
|
|
|
|
for (n = 0; n < MAX_CD_TRACKS; n++)
|
|
|
|
cdRemap[n] = (Uint8)n;
|
|
|
|
CDAudio_GetAudioDiskInfo();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cdValid)
|
|
|
|
{
|
|
|
|
if (CDAudio_GetAudioDiskInfo()==-1 && !cdValid)
|
|
|
|
{
|
|
|
|
CONS_Printf("%s", M_GetText("No CD in drive\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(command, "open", 4))
|
|
|
|
{
|
|
|
|
I_EjectCD();
|
|
|
|
cdValid = SDL_FALSE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(command, "info", 4))
|
|
|
|
{
|
|
|
|
CONS_Printf(M_GetText("%u tracks\n"), maxTrack);
|
|
|
|
if (cdPlaying)
|
|
|
|
CONS_Printf(M_GetText("Currently %s track %u\n"), playLooping ? M_GetText("looping") : M_GetText("playing"), playTrack);
|
|
|
|
else if (wasPlaying)
|
|
|
|
CONS_Printf(M_GetText("Paused %s track %u\n"), playLooping ? M_GetText("looping") : M_GetText("playing"), playTrack);
|
|
|
|
CONS_Printf(M_GetText("Volume is %d\n"), cdvolume);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(command, "play", 4))
|
|
|
|
{
|
|
|
|
I_PlayCD((UINT8)atoi(COM_Argv (2)), SDL_FALSE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(command, "loop", 4))
|
|
|
|
{
|
|
|
|
I_PlayCD((UINT8)atoi(COM_Argv (2)), true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(command, "stop", 4))
|
|
|
|
{
|
|
|
|
I_StopCD();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!strncmp(command, "pause", 5))
|
|
|
|
{
|
|
|
|
I_PauseCD();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(command, "resume", 6))
|
|
|
|
{
|
|
|
|
I_ResumeCD();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CONS_Printf(M_GetText("Invalid CD command \"CD %s\"\n"), COM_Argv(1));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: StopCD
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
*
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
void I_StopCD(void)
|
|
|
|
{
|
|
|
|
#ifndef NOSDLCD
|
|
|
|
if (!cdrom || !cdEnabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!(cdPlaying || wasPlaying))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (SDL_CDStop(cdrom))
|
|
|
|
I_OutputMsg("cdromstop failed\n");
|
|
|
|
|
|
|
|
wasPlaying = SDL_FALSE;
|
|
|
|
cdPlaying = SDL_FALSE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: PauseCD
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
*
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
void I_PauseCD (void)
|
|
|
|
{
|
|
|
|
#ifndef NOSDLCD
|
|
|
|
if (!cdrom || !cdEnabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!cdPlaying)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (SDL_CDPause(cdrom))
|
|
|
|
I_OutputMsg("cdrompause failed\n");
|
|
|
|
|
|
|
|
wasPlaying = cdPlaying;
|
|
|
|
cdPlaying = SDL_FALSE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: ResumeCD
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
*
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
// continue after a pause
|
|
|
|
void I_ResumeCD (void)
|
|
|
|
{
|
|
|
|
#ifndef NOSDLCD
|
|
|
|
if (!cdrom || !cdEnabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!cdValid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!wasPlaying)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (cd_volume.value == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (SDL_CDResume(cdrom))
|
|
|
|
I_OutputMsg("cdromresume failed\n");
|
|
|
|
|
|
|
|
cdPlaying = SDL_TRUE;
|
|
|
|
wasPlaying = SDL_FALSE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: ShutdownCD
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
*
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
void I_ShutdownCD (void)
|
|
|
|
{
|
|
|
|
#ifndef NOSDLCD
|
|
|
|
if (!cdaudio_started)
|
|
|
|
return;
|
|
|
|
|
|
|
|
I_StopCD();
|
|
|
|
|
|
|
|
CONS_Printf("I_ShutdownCD: ");
|
|
|
|
SDL_CDClose(cdrom);
|
|
|
|
cdrom = NULL;
|
|
|
|
cdaudio_started = false;
|
|
|
|
CONS_Printf("%s", M_GetText("shut down\n"));
|
|
|
|
SDL_QuitSubSystem(SDL_INIT_CDROM);
|
|
|
|
cdEnabled = SDL_FALSE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: InitCD
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
* Initialize the first CD drive SDL detects and add console command 'cd'
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
void I_InitCD (void)
|
|
|
|
{
|
|
|
|
#ifndef NOSDLCD
|
|
|
|
INT32 i;
|
|
|
|
|
|
|
|
// Has been checked in d_main.c, but doesn't hurt here
|
|
|
|
if (M_CheckParm ("-nocd"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
CONS_Printf("%s", M_GetText("I_InitCD: Init CD audio\n"));
|
|
|
|
|
|
|
|
// Initialize SDL first
|
|
|
|
if (SDL_InitSubSystem(SDL_INIT_CDROM) < 0)
|
|
|
|
{
|
|
|
|
CONS_Printf(M_GetText("Couldn't initialize SDL CDROM: %s\n"), SDL_GetError());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open drive
|
|
|
|
cdrom = SDL_CDOpen(0);
|
|
|
|
|
|
|
|
if (!cdrom)
|
|
|
|
{
|
|
|
|
const char *cdName = SDL_CDName(0);
|
|
|
|
if (!cdName)
|
|
|
|
CONS_Printf(M_GetText("Couldn't open CD-ROM drive %s: %s\n"), "\b", SDL_GetError());
|
|
|
|
else
|
|
|
|
CONS_Printf(M_GetText("Couldn't open CD-ROM drive %s: %s\n"), cdName, SDL_GetError());
|
|
|
|
//return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_CD_TRACKS; i++)
|
|
|
|
cdRemap[i] = (Uint8)i;
|
|
|
|
|
|
|
|
cdaudio_started = true;
|
|
|
|
if (cdrom) cdEnabled = SDL_TRUE;
|
|
|
|
|
|
|
|
if (CDAudio_GetAudioDiskInfo()==-1)
|
|
|
|
{
|
|
|
|
CONS_Printf("%s", M_GetText("No CD in drive\n"));
|
|
|
|
cdValid = SDL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
COM_AddCommand ("cd", Command_Cd_f);
|
|
|
|
|
|
|
|
CONS_Printf("%s", M_GetText("CD audio Initialized\n"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: UpdateCD
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
* sets CD volume (may have changed) and initiates play evey 2 seconds
|
|
|
|
* in case the song has elapsed
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
void I_UpdateCD (void)
|
|
|
|
{
|
|
|
|
#ifndef NOSDLCD
|
|
|
|
static Uint32 lastchk = 0;
|
|
|
|
|
|
|
|
if (!cdEnabled || !cdrom)
|
|
|
|
return;
|
|
|
|
|
|
|
|
I_SetVolumeCD(cd_volume.value);
|
|
|
|
|
|
|
|
if (cdPlaying && lastchk < SDL_GetTicks())
|
|
|
|
{
|
|
|
|
lastchk = SDL_GetTicks() + 2000; //two seconds between chks
|
|
|
|
|
|
|
|
if (CDAudio_GetAudioDiskInfo()==-1)
|
|
|
|
{
|
|
|
|
cdPlaying = SDL_FALSE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cdStatus != CD_PLAYING && cdStatus != CD_PAUSED)
|
|
|
|
{
|
|
|
|
cdPlaying = SDL_FALSE;
|
|
|
|
if (playLooping)
|
|
|
|
I_PlayCD(playTrack, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: PlayCD
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
* play the requested track and set the looping flag
|
|
|
|
* pauses the CD if volume is 0
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
void I_PlayCD (UINT8 track, UINT8 looping)
|
|
|
|
{
|
|
|
|
#ifdef NOSDLCD
|
|
|
|
(void)track;
|
|
|
|
(void)looping;
|
|
|
|
#else
|
|
|
|
if (!cdrom || !cdEnabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!cdValid)
|
|
|
|
{
|
|
|
|
CDAudio_GetAudioDiskInfo();
|
|
|
|
if (!cdValid)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
track = cdRemap[track];
|
|
|
|
|
|
|
|
if (track < 1 || track > maxTrack)
|
|
|
|
{
|
|
|
|
CONS_Printf(M_GetText("Bad track number %u.\n"), track);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// don't try to play a non-audio track
|
|
|
|
if (cdrom->track[track].type == SDL_DATA_TRACK)
|
|
|
|
{
|
|
|
|
CONS_Printf(M_GetText("Track %u is not audio\n"), track);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cdPlaying)
|
|
|
|
{
|
|
|
|
if (playTrack == track)
|
|
|
|
return;
|
|
|
|
I_StopCD();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SDL_CDPlayTracks(cdrom, track, 0, 1, 0))
|
|
|
|
{
|
|
|
|
CONS_Printf(M_GetText("Error playing track %d: %s\n"), track, SDL_GetError());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
playLooping = looping;
|
|
|
|
playTrack = (Uint8)track;
|
|
|
|
cdPlaying = SDL_TRUE;
|
|
|
|
|
|
|
|
if (cd_volume.value == 0)
|
|
|
|
I_PauseCD();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* function: SetVolumeCD
|
|
|
|
*
|
|
|
|
* description:
|
|
|
|
* SDL does not support setting the CD volume
|
|
|
|
* use pause instead and toggle between full and no music
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
boolean I_SetVolumeCD (INT32 volume)
|
|
|
|
{
|
|
|
|
#ifdef NOSDLCD
|
|
|
|
(void)volume;
|
|
|
|
#else
|
|
|
|
if (volume != cdvolume)
|
|
|
|
{
|
|
|
|
if (volume > 0 && volume < 16)
|
|
|
|
{
|
|
|
|
CV_SetValue(&cd_volume, 31);
|
|
|
|
cdvolume = 31;
|
|
|
|
I_ResumeCD();
|
|
|
|
}
|
|
|
|
else if (volume > 15 && volume < 31)
|
|
|
|
{
|
|
|
|
CV_SetValue(&cd_volume, 0);
|
|
|
|
cdvolume = 0;
|
|
|
|
I_PauseCD();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|