common: prevent buffer overflow
[supercollider.git] / server / scsynth / SC_SequencedCommand.cpp
blob9a0aa13e459419b3f104f619bd542e1127c8a6b2
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SC_SequencedCommand.h"
23 #include "SC_CoreAudio.h"
24 #include "SC_Errors.h"
25 #include "scsynthsend.h"
26 #include "SC_Prototypes.h"
27 #include "SC_HiddenWorld.h"
28 #include "SC_Sem.h"
29 #include "SC_DirUtils.h"
30 #include "SC_StringParser.h"
32 #define GET_COMPLETION_MSG(msg) \
33 mMsgSize = msg.getbsize(); \
34 if (mMsgSize) { \
35 mMsgData = (char*)World_Alloc(mWorld, mMsgSize); \
36 msg.getb(mMsgData, mMsgSize); \
39 void PerformCompletionMsg(World *inWorld, OSC_Packet *inPacket);
41 #define SEND_COMPLETION_MSG \
42 if (mMsgSize) { \
43 OSC_Packet packet; \
44 packet.mData = mMsgData; \
45 packet.mSize = mMsgSize; \
46 packet.mReplyAddr = mReplyAddress; \
47 PacketStatus status = PerformCompletionMsg(mWorld, packet); \
48 if (status == PacketScheduled) { \
49 mMsgSize = 0; \
50 mMsgData = 0; \
51 } \
54 void SndBuf_Init(SndBuf *buf);
55 void SndBuf_Init(SndBuf *buf)
57 buf->data = 0;
58 buf->channels = 0;
59 buf->samples = 0;
60 buf->frames = 0;
61 buf->mask = 0;
62 buf->mask1 = 0;
63 buf->coord = 0;
64 buf->sndfile = 0;
67 char* allocAndRestrictPath(World *mWorld, const char* inPath, const char* restrictBase);
68 char* allocAndRestrictPath(World *mWorld, const char* inPath, const char* restrictBase){
69 char strbuf[PATH_MAX];
70 int offset = 0;
71 int remain = PATH_MAX;
73 // Ensure begins with the base
74 if(strncmp(inPath, restrictBase, strlen(restrictBase)) != 0){
75 strcpy(strbuf, restrictBase);
76 offset = strlen(restrictBase);
77 remain -= offset;
78 if(inPath[0]!='/' && strbuf[strlen(strbuf)-1]!='/'){
79 strbuf[offset] = '/';
80 ++offset;
81 --remain;
85 // Now copy string, but discard any ".." (which could be benign, but easy to abuse)
86 SC_StringParser sp(inPath, '/');
87 size_t tokenlen;
88 while (!sp.AtEnd()) {
89 const char *token = const_cast<char *>(sp.NextToken());
90 tokenlen = strlen(token);
91 // now add the new token, then a slash, as long as token is neither dodgy nor overflows
92 if(strcmp(token, "..")!=0 && remain > tokenlen){
93 strcpy(strbuf+offset, token);
94 offset += tokenlen;
95 remain -= tokenlen;
96 if(!sp.AtEnd()) {
97 strbuf[offset] = '/';
98 ++offset;
99 --remain;
104 // Now we can make a long-term home for the string and return it
105 char* saferPath = (char*)World_Alloc(mWorld, strlen(strbuf)+1);
106 strcpy(saferPath, strbuf);
107 return saferPath;
110 SC_SequencedCommand::SC_SequencedCommand(World *inWorld, ReplyAddress *inReplyAddress)
111 : mNextStage(1), mWorld(inWorld),
112 mMsgSize(0), mMsgData(0)
114 if (inReplyAddress) mReplyAddress = *inReplyAddress;
115 else mReplyAddress.mReplyFunc = null_reply_func;
118 SC_SequencedCommand::~SC_SequencedCommand()
120 if (mMsgData) World_Free(mWorld, mMsgData);
123 int SC_SequencedCommand::Init(char* /*inData*/, int /*inSize*/)
125 return kSCErr_None;
128 void SC_SequencedCommand::SendDone(const char *inCommandName)
130 ::SendDone(&mReplyAddress, inCommandName);
133 void SC_SequencedCommand::SendDoneWithIntValue(const char *inCommandName, int value)
135 ::SendDoneWithIntValue(&mReplyAddress, inCommandName, value);
138 void SC_SequencedCommand::CallEveryStage()
140 switch (mNextStage) {
141 case 1 : if (!Stage1()) break; mNextStage++;
142 case 2 : if (!Stage2()) break; mNextStage++;
143 case 3 : if (!Stage3()) break; mNextStage++;
144 case 4 : Stage4(); break;
146 Delete();
149 void DoSequencedCommand(FifoMsg *inMsg);
150 void DoSequencedCommand(FifoMsg *inMsg)
152 SC_SequencedCommand *cmd = (SC_SequencedCommand*)inMsg->mData;
153 cmd->CallNextStage();
156 void FreeSequencedCommand(FifoMsg *inMsg);
157 void FreeSequencedCommand(FifoMsg *inMsg)
159 SC_SequencedCommand *cmd = (SC_SequencedCommand*)inMsg->mData;
160 cmd->Delete();
164 void SC_SequencedCommand::CallNextStage()
166 bool sendAgain = false;
167 FifoMsg msg;
169 int isRealTime = mNextStage & 1;
170 switch (mNextStage) {
171 case 1 :
172 sendAgain = Stage1(); // RT
173 break;
174 case 2 :
175 sendAgain = Stage2(); // NRT
176 break;
177 case 3 :
178 sendAgain = Stage3(); // RT
179 break;
180 case 4 :
181 Stage4(); // NRT
182 break;
184 mNextStage++;
185 SC_AudioDriver *driver = AudioDriver(mWorld);
186 if (sendAgain) {
187 msg.Set(mWorld, DoSequencedCommand, 0, (void*)this);
188 // send this to next time.
189 if (isRealTime) {
190 // send to NRT
191 driver->SendMsgFromEngine(msg);
192 } else {
193 // send to RT
194 driver->SendMsgToEngine(msg);
196 } else {
197 if (isRealTime) {
198 Delete();
199 } else {
200 // can only be freed from RT.
201 msg.Set(mWorld, FreeSequencedCommand, 0, (void*)this);
202 driver->SendMsgToEngine(msg);
207 void SC_SequencedCommand::Delete()
209 CallDestructor();
210 World_Free(mWorld, this);
213 bool SC_SequencedCommand::Stage1()
215 return true;
218 bool SC_SequencedCommand::Stage2()
220 return false;
223 bool SC_SequencedCommand::Stage3()
225 return false;
228 void SC_SequencedCommand::Stage4()
233 ///////////////////////////////////////////////////////////////////////////
235 #include "sc_msg_iter.h"
236 #include <string.h>
238 SyncCmd::SyncCmd(World *inWorld, ReplyAddress *inReplyAddress)
239 : SC_SequencedCommand(inWorld, inReplyAddress)
243 int SyncCmd::Init(char *inData, int inSize)
245 sc_msg_iter msg(inSize, inData);
246 mID = msg.geti();
247 return kSCErr_None;
250 void SyncCmd::CallDestructor()
252 this->~SyncCmd();
255 bool SyncCmd::Stage2()
257 return true;
260 bool SyncCmd::Stage3()
262 return true;
265 void SyncCmd::Stage4()
267 small_scpacket packet;
268 packet.adds("/synced");
269 packet.maketags(2);
270 packet.addtag(',');
271 packet.addtag('i');
273 packet.addi(mID);
275 SendReply(&mReplyAddress, packet.data(), packet.size());
278 ///////////////////////////////////////////////////////////////////////////
280 BufAllocCmd::BufAllocCmd(World *inWorld, ReplyAddress *inReplyAddress)
281 : SC_SequencedCommand(inWorld, inReplyAddress)
285 int BufAllocCmd::Init(char *inData, int inSize)
287 sc_msg_iter msg(inSize, inData);
288 mBufIndex = msg.geti();
289 mNumFrames = msg.geti();
290 mNumChannels = msg.geti(1);
292 GET_COMPLETION_MSG(msg);
294 return kSCErr_None;
297 void BufAllocCmd::CallDestructor()
299 this->~BufAllocCmd();
302 bool BufAllocCmd::Stage2()
304 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
305 mFreeData = buf->data;
306 bufAlloc(buf, mNumChannels, mNumFrames, mWorld->mFullRate.mSampleRate);
307 mSndBuf = *buf;
308 return true;
311 bool BufAllocCmd::Stage3()
313 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
314 *buf = mSndBuf;
315 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
316 SEND_COMPLETION_MSG;
317 return true;
320 void BufAllocCmd::Stage4()
322 free(mFreeData);
323 SendDoneWithIntValue("/b_alloc", mBufIndex);
326 ///////////////////////////////////////////////////////////////////////////
328 #include "sc_msg_iter.h"
329 #include <string.h>
331 BufGenCmd::BufGenCmd(World *inWorld, ReplyAddress *inReplyAddress)
332 : SC_SequencedCommand(inWorld, inReplyAddress),
333 mData(0)
337 BufGenCmd::~BufGenCmd()
339 World_Free(mWorld, mData);
342 int BufGenCmd::Init(char *inData, int inSize)
344 mSize = inSize;
345 mData = (char*)World_Alloc(mWorld, mSize);
346 memcpy(mData, inData, mSize);
348 sc_msg_iter msg(mSize, mData);
349 mBufIndex = msg.geti();
351 int32 *genName = msg.gets4();
352 if (!genName) return kSCErr_WrongArgType;
354 mBufGen = GetBufGen(genName);
355 if (!mBufGen) return kSCErr_BufGenNotFound;
357 mMsg = msg;
359 return kSCErr_None;
362 void BufGenCmd::CallDestructor()
364 this->~BufGenCmd();
367 bool BufGenCmd::Stage2()
369 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
371 mFreeData = buf->data;
372 (*mBufGen->mBufGenFunc)(mWorld, buf, &mMsg);
373 if (buf->data == mFreeData) mFreeData = NULL;
374 mSndBuf = *buf;
375 return true;
378 bool BufGenCmd::Stage3()
380 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
381 *buf = mSndBuf;
382 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
383 return true;
386 void BufGenCmd::Stage4()
388 free(mFreeData);
389 SendDoneWithIntValue("/b_gen", mBufIndex);
393 ///////////////////////////////////////////////////////////////////////////
396 ///////////////////////////////////////////////////////////////////////////
399 BufFreeCmd::BufFreeCmd(World *inWorld, ReplyAddress *inReplyAddress)
400 : SC_SequencedCommand(inWorld, inReplyAddress)
404 int BufFreeCmd::Init(char *inData, int inSize)
406 sc_msg_iter msg(inSize, inData);
407 mBufIndex = msg.geti();
409 GET_COMPLETION_MSG(msg);
411 return kSCErr_None;
414 void BufFreeCmd::CallDestructor()
416 this->~BufFreeCmd();
419 bool BufFreeCmd::Stage2()
421 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
422 mFreeData = buf->data;
423 #ifndef NO_LIBSNDFILE
424 if (buf->sndfile) sf_close(buf->sndfile);
425 #endif
426 SndBuf_Init(buf);
427 return true;
430 bool BufFreeCmd::Stage3()
432 SndBuf *buf = World_GetBuf(mWorld, mBufIndex);
434 SndBuf_Init(buf);
435 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
436 SEND_COMPLETION_MSG;
438 return true;
441 void BufFreeCmd::Stage4()
443 free(mFreeData);
444 SendDoneWithIntValue("/b_free", mBufIndex);
447 ///////////////////////////////////////////////////////////////////////////
449 BufZeroCmd::BufZeroCmd(World *inWorld, ReplyAddress *inReplyAddress)
450 : SC_SequencedCommand(inWorld, inReplyAddress)
454 int BufZeroCmd::Init(char *inData, int inSize)
456 sc_msg_iter msg(inSize, inData);
457 mBufIndex = msg.geti();
459 GET_COMPLETION_MSG(msg);
461 return kSCErr_None;
464 void BufZeroCmd::CallDestructor()
466 this->~BufZeroCmd();
469 bool BufZeroCmd::Stage2()
471 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
472 memset(buf->data, 0, buf->samples * sizeof(float));
473 return true;
476 bool BufZeroCmd::Stage3()
478 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
479 SEND_COMPLETION_MSG;
480 return true;
483 void BufZeroCmd::Stage4()
485 SendDoneWithIntValue("/b_zero", mBufIndex);
488 ///////////////////////////////////////////////////////////////////////////
490 BufAllocReadCmd::BufAllocReadCmd(World *inWorld, ReplyAddress *inReplyAddress)
491 : SC_SequencedCommand(inWorld, inReplyAddress), mFreeData(0), mFilename(0)
495 int BufAllocReadCmd::Init(char *inData, int inSize)
497 sc_msg_iter msg(inSize, inData);
498 mBufIndex = msg.geti();
500 const char *filename = msg.gets();
501 if (!filename) return kSCErr_WrongArgType;
503 if(mWorld->mRestrictedPath){
504 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
505 }else{
506 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
507 strcpy(mFilename, filename);
510 mFileOffset = msg.geti();
511 mNumFrames = msg.geti();
513 GET_COMPLETION_MSG(msg);
515 return kSCErr_None;
518 BufAllocReadCmd::~BufAllocReadCmd()
520 World_Free(mWorld, mFilename);
523 void BufAllocReadCmd::CallDestructor()
525 this->~BufAllocReadCmd();
528 bool BufAllocReadCmd::Stage2()
530 #ifdef NO_LIBSNDFILE
531 SendFailure(&mReplyAddress, "/b_allocRead", "scsynth compiled without libsndfile\n");
532 scprintf("scsynth compiled without libsndfile\n");
533 return false;
534 #else
535 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
536 SF_INFO fileinfo;
537 memset(&fileinfo, 0, sizeof(fileinfo));
538 SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo);
539 if (!sf) {
540 char str[256];
541 sprintf(str, "File '%s' could not be opened.\n", mFilename);
542 SendFailureWithBufnum(&mReplyAddress, "/b_allocRead", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str);
543 scprintf(str);
544 return false;
546 if (mFileOffset < 0) mFileOffset = 0;
547 else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames;
548 if (mNumFrames <= 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset;
550 // alloc data size
551 mFreeData = buf->data;
552 SCErr err = bufAlloc(buf, fileinfo.channels, mNumFrames, fileinfo.samplerate);
553 if (err) goto leave;
555 sf_seek(sf, mFileOffset, SEEK_SET);
556 sf_readf_float(sf, buf->data, mNumFrames);
558 leave:
559 mSndBuf = *buf;
560 sf_close(sf);
562 return true;
563 #endif
566 bool BufAllocReadCmd::Stage3()
568 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
569 *buf = mSndBuf;
570 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
571 SEND_COMPLETION_MSG;
573 return true;
576 void BufAllocReadCmd::Stage4()
578 free(mFreeData);
579 SendDoneWithIntValue("/b_allocRead", mBufIndex);
582 ///////////////////////////////////////////////////////////////////////////
584 BufReadCmd::BufReadCmd(World *inWorld, ReplyAddress *inReplyAddress)
585 : SC_SequencedCommand(inWorld, inReplyAddress),
586 mFilename(0)
590 int BufReadCmd::Init(char *inData, int inSize)
592 sc_msg_iter msg(inSize, inData);
593 mBufIndex = msg.geti();
595 const char *filename = msg.gets();
596 if (!filename) return kSCErr_WrongArgType;
598 if(mWorld->mRestrictedPath){
599 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
600 }else{
601 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
602 strcpy(mFilename, filename);
605 mFileOffset = msg.geti();
606 mNumFrames = msg.geti(-1);
607 mBufOffset = msg.geti();
608 mLeaveFileOpen = msg.geti();
610 GET_COMPLETION_MSG(msg);
612 return kSCErr_None;
615 BufReadCmd::~BufReadCmd()
617 World_Free(mWorld, mFilename);
620 void BufReadCmd::CallDestructor()
622 this->~BufReadCmd();
625 bool BufReadCmd::Stage2()
627 #ifdef NO_LIBSNDFILE
628 SendFailure(&mReplyAddress, "/b_read", "scsynth compiled without libsndfile\n");
629 scprintf("scsynth compiled without libsndfile\n");
630 return false;
631 #else
632 SF_INFO fileinfo;
634 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
635 int framesToEnd = buf->frames - mBufOffset;
636 if (framesToEnd <= 0) return true;
638 SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo);
639 if (!sf) {
640 char str[256];
641 sprintf(str, "File '%s' could not be opened.\n", mFilename);
642 SendFailureWithBufnum(&mReplyAddress, "/b_read", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_read", str);
643 scprintf(str);
644 return false;
646 if (fileinfo.channels != buf->channels) {
647 char str[256];
648 sf_close(sf);
649 sprintf(str, "channel mismatch. File'%s' has %d channels. Buffer has %d channels.\n", mFilename, fileinfo.channels, buf->channels);
650 SendFailureWithBufnum(&mReplyAddress, "/b_read", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_read", str);
651 scprintf(str);
652 return false;
655 if (mFileOffset < 0) mFileOffset = 0;
656 else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames;
657 if (mNumFrames < 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset;
659 if (mNumFrames > framesToEnd) mNumFrames = framesToEnd;
661 sf_seek(sf, mFileOffset, SEEK_SET);
662 if (mNumFrames > 0) {
663 sf_readf_float(sf, buf->data + (mBufOffset * buf->channels), mNumFrames);
666 if(buf->sndfile)
667 sf_close(buf->sndfile);
669 if (mLeaveFileOpen) {
670 buf->sndfile = sf;
671 } else {
672 sf_close(sf);
673 buf->sndfile = 0;
676 mSampleRate = (double)fileinfo.samplerate;
678 return true;
679 #endif
682 bool BufReadCmd::Stage3()
684 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
685 buf->samplerate = mSampleRate;
686 if (mLeaveFileOpen) buf->mask = buf->mask1 = -1;
688 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
689 SEND_COMPLETION_MSG;
690 return true;
693 void BufReadCmd::Stage4()
695 SendDoneWithIntValue("/b_read", mBufIndex);
698 ///////////////////////////////////////////////////////////////////////////
700 SC_BufReadCommand::SC_BufReadCommand(World* inWorld, ReplyAddress* inReplyAddress)
701 : SC_SequencedCommand(inWorld, inReplyAddress),
702 mNumChannels(0)
706 SC_BufReadCommand::~SC_BufReadCommand()
710 void SC_BufReadCommand::InitChannels(sc_msg_iter& msg)
712 mNumChannels = 0;
713 while (msg.nextTag(0) == 'i') {
714 int c = msg.geti();
715 if (mNumChannels <= kMaxNumChannels) {
716 mChannels[mNumChannels++] = c;
721 bool SC_BufReadCommand::CheckChannels(int inNumChannels)
723 for (int i=0; i < mNumChannels; ++i) {
724 if (mChannels[i] >= inNumChannels) {
725 return false;
728 return true;
731 void SC_BufReadCommand::CopyChannels(float* dst, float* src, size_t srcChannels, size_t numFrames)
733 for (int ci=0; ci < mNumChannels; ++ci) {
734 int c = mChannels[ci];
735 if (c >= 0 && c < srcChannels) {
736 for (size_t fi=0; fi < numFrames; ++fi) {
737 dst[fi*mNumChannels+ci] = src[fi*srcChannels+c];
739 } else {
740 for (size_t fi=0; fi < numFrames; ++fi) {
741 dst[fi*mNumChannels+ci] = 0.f;
747 ///////////////////////////////////////////////////////////////////////////
749 BufAllocReadChannelCmd::BufAllocReadChannelCmd(World *inWorld, ReplyAddress *inReplyAddress)
750 : SC_BufReadCommand(inWorld, inReplyAddress),
751 mFreeData(0), mFilename(0)
755 int BufAllocReadChannelCmd::Init(char *inData, int inSize)
757 sc_msg_iter msg(inSize, inData);
758 mBufIndex = msg.geti();
760 const char *filename = msg.gets();
761 if (!filename) return kSCErr_WrongArgType;
763 if(mWorld->mRestrictedPath){
764 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
765 }else{
766 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
767 strcpy(mFilename, filename);
770 mFileOffset = msg.geti();
771 mNumFrames = msg.geti();
773 InitChannels(msg);
775 GET_COMPLETION_MSG(msg);
777 return kSCErr_None;
780 BufAllocReadChannelCmd::~BufAllocReadChannelCmd()
782 World_Free(mWorld, mFilename);
785 void BufAllocReadChannelCmd::CallDestructor()
787 this->~BufAllocReadChannelCmd();
790 bool BufAllocReadChannelCmd::Stage2()
792 #ifdef NO_LIBSNDFILE
793 SendFailure(&mReplyAddress, "/b_allocReadChannel", "scsynth compiled without libsndfile\n");
794 scprintf("scsynth compiled without libsndfile\n");
795 return false;
796 #else
797 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
799 SF_INFO fileinfo;
800 memset(&fileinfo, 0, sizeof(fileinfo));
801 SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo);
802 if (!sf) {
803 char str[256];
804 sprintf(str, "File '%s' could not be opened.\n", mFilename);
805 SendFailureWithBufnum(&mReplyAddress, "/b_allocReadChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str);
806 scprintf(str);
807 return false;
809 if (mFileOffset < 0) mFileOffset = 0;
810 else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames;
811 if (mNumFrames <= 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset;
813 if (mNumChannels == 0) {
814 // alloc data size
815 mFreeData = buf->data;
816 SCErr err = bufAlloc(buf, fileinfo.channels, mNumFrames, fileinfo.samplerate);
817 if (err) goto leave;
818 // read all channels
819 sf_seek(sf, mFileOffset, SEEK_SET);
820 sf_readf_float(sf, buf->data, mNumFrames);
821 } else {
822 // verify channel indexes
823 if (!CheckChannels(fileinfo.channels)) {
824 const char* str = "Channel index out of range.\n";
825 SendFailureWithBufnum(&mReplyAddress, "/b_allocReadChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str);
826 scprintf(str);
827 sf_close(sf);
828 return false;
830 // alloc data size
831 mFreeData = buf->data;
832 SCErr err = bufAlloc(buf, mNumChannels, mNumFrames, fileinfo.samplerate);
833 if (err) goto leave;
834 // alloc temp buffer
835 float* data = (float*)malloc(mNumFrames*fileinfo.channels*sizeof(float));
836 if (data == 0) goto leave;
837 // read some channels
838 sf_seek(sf, mFileOffset, SEEK_SET);
839 sf_readf_float(sf, data, mNumFrames);
840 CopyChannels(buf->data, data, fileinfo.channels, mNumFrames);
841 // free temp buffer
842 free(data);
845 leave:
846 mSndBuf = *buf;
847 sf_close(sf);
849 return true;
850 #endif
853 bool BufAllocReadChannelCmd::Stage3()
855 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
856 *buf = mSndBuf;
857 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
858 SEND_COMPLETION_MSG;
860 return true;
863 void BufAllocReadChannelCmd::Stage4()
865 free(mFreeData);
866 SendDoneWithIntValue("/b_allocReadChannel", mBufIndex);
869 ///////////////////////////////////////////////////////////////////////////
871 BufReadChannelCmd::BufReadChannelCmd(World *inWorld, ReplyAddress *inReplyAddress)
872 : SC_BufReadCommand(inWorld, inReplyAddress),
873 mFilename(0)
877 int BufReadChannelCmd::Init(char *inData, int inSize)
879 sc_msg_iter msg(inSize, inData);
880 mBufIndex = msg.geti();
882 const char *filename = msg.gets();
883 if (!filename) return kSCErr_WrongArgType;
885 if(mWorld->mRestrictedPath){
886 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
887 }else{
888 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
889 strcpy(mFilename, filename);
892 mFileOffset = msg.geti();
893 mNumFrames = msg.geti(-1);
894 mBufOffset = msg.geti();
895 mLeaveFileOpen = msg.geti();
897 InitChannels(msg);
899 GET_COMPLETION_MSG(msg);
901 return kSCErr_None;
904 BufReadChannelCmd::~BufReadChannelCmd()
906 World_Free(mWorld, mFilename);
909 void BufReadChannelCmd::CallDestructor()
911 this->~BufReadChannelCmd();
914 bool BufReadChannelCmd::Stage2()
916 #ifdef NO_LIBSNDFILE
917 SendFailure(&mReplyAddress, "/b_readChannel", "scsynth compiled without libsndfile\n");
918 scprintf("scsynth compiled without libsndfile\n");
919 return false;
920 #else
921 SF_INFO fileinfo;
923 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
924 int framesToEnd = buf->frames - mBufOffset;
925 if (framesToEnd <= 0) return true;
927 SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo);
928 if (!sf) {
929 char str[256];
930 sprintf(str, "File '%s' could not be opened.\n", mFilename);
931 SendFailureWithBufnum(&mReplyAddress, "/b_readChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_read", str);
932 scprintf(str);
933 return false;
936 if (mNumChannels > 0) {
937 // verify channel indexes
938 if (!( CheckChannels(fileinfo.channels)) ) { // nescivi: && CheckChannels(buf->channels) (should not check here for buf->channels)
939 const char* str = "Channel index out of range.\n";
940 SendFailureWithBufnum(&mReplyAddress, "/b_readChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str);
941 scprintf(str);
942 sf_close(sf);
943 return false;
945 // nescivi: this also seems out of place: we want to read from a file with more channels than are in the buffer
946 // } else if (fileinfo.channels != buf->channels) {
947 // char str[256];
948 // sf_close(sf);
949 // sprintf(str, "Channel mismatch. File '%s' has %d channels. Buffer has %d channels.\n",
950 // mFilename, fileinfo.channels, buf->channels);
951 // SendFailure(&mReplyAddress, "/b_read", str);
952 // scprintf(str);
953 // return false;
956 if (mFileOffset < 0) mFileOffset = 0;
957 else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames;
958 if (mNumFrames < 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset;
959 if (mNumFrames > framesToEnd) mNumFrames = framesToEnd;
961 sf_seek(sf, mFileOffset, SEEK_SET);
962 if (mNumFrames > 0) {
963 if (mNumChannels == 0) {
964 // read all channels
965 sf_readf_float(sf, buf->data + (mBufOffset * buf->channels), mNumFrames);
966 } else {
967 // alloc temp buffer
968 float* data = (float*)malloc(mNumFrames*fileinfo.channels*sizeof(float));
969 if (data == 0) goto leave;
970 // read some channels
971 sf_seek(sf, mFileOffset, SEEK_SET);
972 sf_readf_float(sf, data, mNumFrames);
973 CopyChannels(buf->data + (mBufOffset * mNumChannels), data, fileinfo.channels, mNumFrames);
974 // free temp buffer
975 free(data);
979 leave:
980 if(buf->sndfile)
981 sf_close(buf->sndfile);
983 if (mLeaveFileOpen) {
984 buf->sndfile = sf;
985 } else {
986 sf_close(sf);
987 buf->sndfile = 0;
990 mSampleRate = (double)fileinfo.samplerate;
992 return true;
993 #endif
996 bool BufReadChannelCmd::Stage3()
998 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
999 buf->samplerate = mSampleRate;
1000 if (mLeaveFileOpen) buf->mask = buf->mask1 = -1;
1002 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
1003 SEND_COMPLETION_MSG;
1004 return true;
1007 void BufReadChannelCmd::Stage4()
1009 SendDoneWithIntValue("/b_readChannel", mBufIndex);
1012 ///////////////////////////////////////////////////////////////////////////
1014 BufWriteCmd::BufWriteCmd(World *inWorld, ReplyAddress *inReplyAddress)
1015 : SC_SequencedCommand(inWorld, inReplyAddress), mFilename(0)
1019 #ifdef NO_LIBSNDFILE
1020 struct SF_INFO {};
1021 #endif
1024 extern "C" {
1025 int sndfileFormatInfoFromStrings(SF_INFO *info, const char *headerFormatString, const char *sampleFormatString);
1029 int BufWriteCmd::Init(char *inData, int inSize)
1031 #ifdef NO_LIBSNDFILE
1032 SendFailure(&mReplyAddress, "/b_write", "scsynth compiled without libsndfile\n");
1033 scprintf("scsynth compiled without libsndfile\n");
1034 return false;
1035 #else
1036 sc_msg_iter msg(inSize, inData);
1037 mBufIndex = msg.geti();
1039 const char *filename = msg.gets();
1040 if (!filename) return kSCErr_WrongArgType;
1042 if(mWorld->mRestrictedPath){
1043 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
1044 }else{
1045 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
1046 strcpy(mFilename, filename);
1049 const char *headerFormatString = msg.gets("aiff");
1050 const char *sampleFormatString = msg.gets("int16");
1052 mNumFrames = msg.geti(-1);
1053 mBufOffset = msg.geti();
1054 mLeaveFileOpen = msg.geti();
1056 GET_COMPLETION_MSG(msg);
1058 memset(&mFileInfo, 0, sizeof(mFileInfo));
1059 return sndfileFormatInfoFromStrings(&mFileInfo, headerFormatString, sampleFormatString);
1060 #endif
1063 BufWriteCmd::~BufWriteCmd()
1065 World_Free(mWorld, mFilename);
1068 void BufWriteCmd::CallDestructor()
1070 this->~BufWriteCmd();
1073 bool BufWriteCmd::Stage2()
1075 #ifdef NO_LIBSNDFILE
1076 return false;
1077 #else
1078 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
1079 int framesToEnd = buf->frames - mBufOffset;
1080 if (framesToEnd < 0) framesToEnd = 0;
1081 mFileInfo.samplerate = (int)buf->samplerate;
1082 mFileInfo.channels = buf->channels;
1084 SNDFILE* sf = sf_open(mFilename, SFM_WRITE, &mFileInfo);
1085 if (!sf) {
1086 char sferr[256];
1087 char str[256];
1088 sf_error_str(NULL, sferr, 256);
1089 sprintf(str, "File '%s' could not be opened. '%s'\n", mFilename, sferr);
1090 SendFailureWithBufnum(&mReplyAddress, "/b_write", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_write", str);
1091 scprintf(str);
1092 return false;
1095 if (mNumFrames < 0 || mNumFrames > buf->frames) mNumFrames = buf->frames;
1097 if (mNumFrames > framesToEnd) mNumFrames = framesToEnd;
1099 if (mNumFrames > 0) {
1100 sf_writef_float(sf, buf->data + (mBufOffset * buf->channels), mNumFrames);
1103 if(buf->sndfile)
1104 sf_close(buf->sndfile);
1106 if (mLeaveFileOpen) {
1107 buf->sndfile = sf;
1108 } else {
1109 sf_close(sf);
1110 buf->sndfile = 0;
1113 return true;
1114 #endif
1117 bool BufWriteCmd::Stage3()
1119 SEND_COMPLETION_MSG;
1120 return true;
1123 void BufWriteCmd::Stage4()
1125 SendDoneWithIntValue("/b_write", mBufIndex);
1128 ///////////////////////////////////////////////////////////////////////////
1130 BufCloseCmd::BufCloseCmd(World *inWorld, ReplyAddress *inReplyAddress)
1131 : SC_SequencedCommand(inWorld, inReplyAddress)
1135 int BufCloseCmd::Init(char *inData, int inSize)
1137 sc_msg_iter msg(inSize, inData);
1138 mBufIndex = msg.geti();
1140 GET_COMPLETION_MSG(msg);
1142 return kSCErr_None;
1145 void BufCloseCmd::CallDestructor()
1147 this->~BufCloseCmd();
1150 bool BufCloseCmd::Stage2()
1152 #ifdef NO_LIBSNDFILE
1153 SendFailure(&mReplyAddress, "/b_close", "scsynth compiled without libsndfile\n");
1154 scprintf("scsynth compiled without libsndfile\n");
1155 return false;
1156 #else
1157 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
1158 if (buf->sndfile) {
1159 sf_close(buf->sndfile);
1160 buf->sndfile = 0;
1162 return true;
1163 #endif
1166 bool BufCloseCmd::Stage3()
1168 SEND_COMPLETION_MSG;
1169 return true;
1172 void BufCloseCmd::Stage4()
1174 SendDoneWithIntValue("/b_close", mBufIndex);
1177 ///////////////////////////////////////////////////////////////////////////
1179 AudioQuitCmd::AudioQuitCmd(World *inWorld, ReplyAddress *inReplyAddress)
1180 : SC_SequencedCommand(inWorld, inReplyAddress)
1184 void AudioQuitCmd::CallDestructor()
1186 this->~AudioQuitCmd();
1189 bool AudioQuitCmd::Stage2()
1191 mWorld->hw->mTerminating = true;
1192 return true;
1195 bool AudioQuitCmd::Stage3()
1197 #if SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
1198 SendFailure(&mReplyAddress, "/quit", "not allowed in AU host\n");
1199 scprintf("/quit : quit not allowed in AU host\n");
1200 return false;
1201 #else
1202 return true;
1203 #endif
1206 void AudioQuitCmd::Stage4()
1208 SendDone("/quit");
1209 mWorld->hw->mQuitProgram->Release();
1212 ///////////////////////////////////////////////////////////////////////////
1214 AudioStatusCmd::AudioStatusCmd(World *inWorld, ReplyAddress *inReplyAddress)
1215 : SC_SequencedCommand(inWorld, inReplyAddress)
1219 void AudioStatusCmd::CallDestructor()
1221 this->~AudioStatusCmd();
1224 bool AudioStatusCmd::Stage2()
1226 // we stop replying to status requests after receiving /quit
1227 if (mWorld->hw->mTerminating == true)
1228 return false;
1230 small_scpacket packet;
1231 packet.adds("/status.reply");
1232 packet.maketags(10);
1233 packet.addtag(',');
1234 packet.addtag('i');
1235 packet.addtag('i');
1236 packet.addtag('i');
1237 packet.addtag('i');
1238 packet.addtag('i');
1239 packet.addtag('f');
1240 packet.addtag('f');
1241 packet.addtag('d');
1242 packet.addtag('d');
1244 packet.addi(1); // audio is always active now.
1245 packet.addi(mWorld->mNumUnits);
1246 packet.addi(mWorld->mNumGraphs);
1247 packet.addi(mWorld->mNumGroups);
1248 packet.addi(mWorld->hw->mGraphDefLib->NumItems());
1250 SC_AudioDriver *driver = mWorld->hw->mAudioDriver;
1251 packet.addf(driver->GetAvgCPU());
1252 packet.addf(driver->GetPeakCPU());
1253 packet.addd(driver->GetSampleRate());
1254 packet.addd(driver->GetActualSampleRate());
1256 SendReply(&mReplyAddress, packet.data(), packet.size());
1258 return false;
1261 ///////////////////////////////////////////////////////////////////////////
1263 NotifyCmd::NotifyCmd(World *inWorld, ReplyAddress *inReplyAddress)
1264 : SC_SequencedCommand(inWorld, inReplyAddress)
1268 int NotifyCmd::Init(char *inData, int inSize)
1270 sc_msg_iter msg(inSize, inData);
1271 mOnOff = msg.geti();
1273 return kSCErr_None;
1276 void NotifyCmd::CallDestructor()
1278 this->~NotifyCmd();
1281 bool NotifyCmd::Stage2()
1283 HiddenWorld *hw = mWorld->hw;
1285 if (mOnOff) {
1286 for (uint32 i=0; i<hw->mNumUsers; ++i) {
1287 if (mReplyAddress == hw->mUsers[i]) {
1288 // already in table - don't fail though..
1289 SendFailure(&mReplyAddress, "/notify", "notify: already registered\n");
1290 scprintf("/notify : already registered\n");
1291 return false;
1295 // add reply address to user table
1296 if (hw->mNumUsers >= hw->mMaxUsers) {
1297 SendFailure(&mReplyAddress, "/notify", "too many users\n");
1298 scprintf("too many users\n");
1299 return false;
1302 hw->mUsers[hw->mNumUsers++] = mReplyAddress;
1304 SendDone("/notify");
1305 } else {
1306 for (uint32 i=0; i<hw->mNumUsers; ++i) {
1307 if (mReplyAddress == hw->mUsers[i]) {
1308 // remove from list
1309 hw->mUsers[i] = hw->mUsers[--hw->mNumUsers];
1310 SendDone("/notify");
1311 return false;
1315 SendFailure(&mReplyAddress, "/notify", "not registered\n");
1316 scprintf("not registered\n");
1318 return false;
1321 ///////////////////////////////////////////////////////////////////////////
1323 SendFailureCmd::SendFailureCmd(World *inWorld, ReplyAddress *inReplyAddress)
1324 : SC_SequencedCommand(inWorld, inReplyAddress), mCmdName(0), mErrString(0)
1328 SendFailureCmd::~SendFailureCmd()
1330 World_Free(mWorld, mCmdName);
1331 World_Free(mWorld, mErrString);
1335 void SendFailureCmd::InitSendFailureCmd(const char *inCmdName, const char* inErrString)
1337 mCmdName = (char*)World_Alloc(mWorld, strlen(inCmdName)+1);
1338 strcpy(mCmdName, inCmdName);
1340 mErrString = (char*)World_Alloc(mWorld, strlen(inErrString)+1);
1341 strcpy(mErrString, inErrString);
1344 void SendFailureCmd::CallDestructor()
1346 this->~SendFailureCmd();
1349 bool SendFailureCmd::Stage2()
1351 SendFailure(&mReplyAddress, mCmdName, mErrString);
1352 return false;
1355 ///////////////////////////////////////////////////////////////////////////
1357 RecvSynthDefCmd::RecvSynthDefCmd(World *inWorld, ReplyAddress *inReplyAddress)
1358 : SC_SequencedCommand(inWorld, inReplyAddress), mBuffer(0)
1362 int RecvSynthDefCmd::Init(char *inData, int inSize)
1364 sc_msg_iter msg(inSize, inData);
1366 int size = msg.getbsize();
1367 if (!size) throw kSCErr_WrongArgType;
1369 mBuffer = (char*)World_Alloc(mWorld, size);
1370 msg.getb(mBuffer, size);
1372 GET_COMPLETION_MSG(msg);
1374 mDefs = 0;
1375 return kSCErr_None;
1378 RecvSynthDefCmd::~RecvSynthDefCmd()
1380 World_Free(mWorld, mBuffer);
1383 void RecvSynthDefCmd::CallDestructor()
1385 this->~RecvSynthDefCmd();
1388 bool RecvSynthDefCmd::Stage2()
1390 mDefs = GraphDef_Recv(mWorld, mBuffer, mDefs);
1392 return true;
1395 bool RecvSynthDefCmd::Stage3()
1397 GraphDef_Define(mWorld, mDefs);
1398 SEND_COMPLETION_MSG;
1399 return true;
1402 void RecvSynthDefCmd::Stage4()
1404 SendDone("/d_recv");
1407 ///////////////////////////////////////////////////////////////////////////
1409 LoadSynthDefCmd::LoadSynthDefCmd(World *inWorld, ReplyAddress *inReplyAddress)
1410 : SC_SequencedCommand(inWorld, inReplyAddress), mFilename(0)
1414 int LoadSynthDefCmd::Init(char *inData, int inSize)
1416 sc_msg_iter msg(inSize, inData);
1418 const char *filename = msg.gets();
1419 if (!filename) return kSCErr_WrongArgType;
1421 if(mWorld->mRestrictedPath){
1422 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
1423 }else{
1424 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
1425 strcpy(mFilename, filename);
1428 GET_COMPLETION_MSG(msg);
1430 mDefs = 0;
1431 return kSCErr_None;
1434 LoadSynthDefCmd::~LoadSynthDefCmd()
1436 World_Free(mWorld, mFilename);
1439 void LoadSynthDefCmd::CallDestructor()
1441 this->~LoadSynthDefCmd();
1444 bool LoadSynthDefCmd::Stage2()
1446 char* fname = mFilename;
1447 mDefs = GraphDef_LoadGlob(mWorld, fname, mDefs);
1448 return true;
1451 bool LoadSynthDefCmd::Stage3()
1453 GraphDef_Define(mWorld, mDefs);
1454 SEND_COMPLETION_MSG;
1455 return true;
1458 void LoadSynthDefCmd::Stage4()
1460 SendDone("/d_load");
1463 ///////////////////////////////////////////////////////////////////////////
1465 LoadSynthDefDirCmd::LoadSynthDefDirCmd(World *inWorld, ReplyAddress *inReplyAddress)
1466 : SC_SequencedCommand(inWorld, inReplyAddress), mFilename(0)
1470 int LoadSynthDefDirCmd::Init(char *inData, int inSize)
1472 sc_msg_iter msg(inSize, inData);
1474 const char *filename = msg.gets();
1475 if (!filename) return kSCErr_WrongArgType;
1477 if(mWorld->mRestrictedPath){
1478 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
1479 }else{
1480 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
1481 strcpy(mFilename, filename);
1484 GET_COMPLETION_MSG(msg);
1486 mDefs = 0;
1487 return kSCErr_None;
1490 LoadSynthDefDirCmd::~LoadSynthDefDirCmd()
1492 World_Free(mWorld, mFilename);
1495 void LoadSynthDefDirCmd::CallDestructor()
1497 this->~LoadSynthDefDirCmd();
1500 bool LoadSynthDefDirCmd::Stage2()
1502 mDefs = GraphDef_LoadDir(mWorld, mFilename, mDefs);
1504 return true;
1507 bool LoadSynthDefDirCmd::Stage3()
1509 GraphDef_Define(mWorld, mDefs);
1510 SEND_COMPLETION_MSG;
1511 return true;
1514 void LoadSynthDefDirCmd::Stage4()
1516 SendDone("/d_loadDir");
1519 ///////////////////////////////////////////////////////////////////////////
1521 SendReplyCmd::SendReplyCmd(World *inWorld, ReplyAddress *inReplyAddress)
1522 : SC_SequencedCommand(inWorld, inReplyAddress)
1526 int SendReplyCmd::Init(char *inData, int inSize)
1528 mMsgSize = inSize;
1529 mMsgData = (char*)World_Alloc(mWorld, mMsgSize);
1530 memcpy(mMsgData, inData, inSize);
1531 return kSCErr_None;
1534 void SendReplyCmd::CallDestructor()
1536 this->~SendReplyCmd();
1539 bool SendReplyCmd::Stage2()
1541 SendReply(&mReplyAddress, mMsgData, mMsgSize);
1542 return false;
1545 ///////////////////////////////////////////////////////////////////////////
1547 int PerformAsynchronousCommand(
1548 World *inWorld,
1549 void* replyAddr,
1550 const char* cmdName,
1551 void *cmdData,
1552 AsyncStageFn stage2, // stage2 is non real time
1553 AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true
1554 AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true
1555 AsyncFreeFn cleanup,
1556 int completionMsgSize,
1557 void* completionMsgData
1560 void* space = World_Alloc(inWorld, sizeof(AsyncPlugInCmd));
1561 AsyncPlugInCmd *cmd = new (space) AsyncPlugInCmd(inWorld, (ReplyAddress*)replyAddr,
1562 cmdName, cmdData, stage2, stage3, stage4, cleanup,
1563 completionMsgSize, completionMsgData);
1564 if (!cmd) return kSCErr_Failed;
1565 if (inWorld->mRealTime) cmd->CallNextStage();
1566 else cmd->CallEveryStage();
1567 return kSCErr_None;
1570 ///////////////////////////////////////////////////////////////////////////
1572 AsyncPlugInCmd::AsyncPlugInCmd(World *inWorld, ReplyAddress *inReplyAddress,
1573 const char* cmdName,
1574 void *cmdData,
1575 AsyncStageFn stage2, // stage2 is non real time
1576 AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true
1577 AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true
1578 AsyncFreeFn cleanup, // cleanup is called in real time
1579 int completionMsgSize,
1580 void* completionMsgData)
1581 : SC_SequencedCommand(inWorld, inReplyAddress),
1582 mCmdName(cmdName), mCmdData(cmdData),
1583 mStage2(stage2), mStage3(stage3), mStage4(stage4),
1584 mCleanup(cleanup)
1586 if (completionMsgSize && completionMsgData) {
1587 mMsgSize = completionMsgSize;
1588 mMsgData = (char*)World_Alloc(mWorld, mMsgSize);
1589 memcpy(mMsgData, completionMsgData, mMsgSize);
1593 AsyncPlugInCmd::~AsyncPlugInCmd()
1595 (mCleanup)(mWorld, mCmdData);
1596 if (mMsgData) World_Free(mWorld, mMsgData);
1599 void AsyncPlugInCmd::CallDestructor()
1601 this->~AsyncPlugInCmd();
1604 bool AsyncPlugInCmd::Stage2()
1606 bool result = !mStage2 || (mStage2)(mWorld, mCmdData);
1607 return result;
1610 bool AsyncPlugInCmd::Stage3()
1612 bool result = !mStage3 || (mStage3)(mWorld, mCmdData);
1613 if (result) SEND_COMPLETION_MSG;
1614 return result;
1617 void AsyncPlugInCmd::Stage4()
1619 bool result = !mStage4 || (mStage4)(mWorld, mCmdData);
1620 if (result && mCmdName && mReplyAddress.mReplyFunc != null_reply_func) SendDone((char*)mCmdName);