/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Darin Fisher * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsIComponentRegistrar.h" #include "nsIStreamTransportService.h" #include "nsIAsyncInputStream.h" #include "nsIProgressEventSink.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIProxyObjectManager.h" #include "nsIRequest.h" #include "nsIServiceManager.h" #include "nsIComponentManager.h" #include "nsCOMPtr.h" #include "nsMemory.h" #include "nsString.h" #include "nsIFileStreams.h" #include "nsIStreamListener.h" #include "nsIEventQueueService.h" #include "nsIEventQueue.h" #include "nsILocalFile.h" #include "nsNetUtil.h" #include "nsAutoLock.h" #include "prlog.h" #include "prenv.h" //////////////////////////////////////////////////////////////////////////////// #if defined(PR_LOGGING) // // set NSPR_LOG_MODULES=Test:5 // static PRLogModuleInfo *gTestLog = nsnull; #endif #define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args) //////////////////////////////////////////////////////////////////////////////// static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID); static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_CID(kEventQueueCID, NS_EVENTQUEUE_CID); PRBool gDone = PR_FALSE; nsIEventQueue* gEventQ = nsnull; //////////////////////////////////////////////////////////////////////////////// static void *PR_CALLBACK DoneEvent_Handler(PLEvent *ev) { gDone = PR_TRUE; return nsnull; } static void PR_CALLBACK DoneEvent_Cleanup(PLEvent *ev) { delete ev; } static void PostDoneEvent() { LOG(("PostDoneEvent\n")); PLEvent *ev = new PLEvent(); PL_InitEvent(ev, nsnull, DoneEvent_Handler, DoneEvent_Cleanup); gEventQ->PostEvent(ev); } //////////////////////////////////////////////////////////////////////////////// #define CHUNK_SIZE 500 class MyCopier : public nsIInputStreamNotify , public nsIOutputStreamNotify { public: NS_DECL_ISUPPORTS MyCopier() : mLock(nsnull) , mInputCondition(NS_OK) { } virtual ~MyCopier() { if (mLock) PR_DestroyLock(mLock); if (mInput) mInput->Close(); if (mOutput) mOutput->Close(); } // called on any thread NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *inStr) { LOG(("OnInputStreamReady\n")); nsAutoLock lock(mLock); NS_ASSERTION(inStr == mInput, "unexpected stream"); Process_Locked(); return NS_OK; } // called on any thread NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *outStr) { LOG(("OnOutputStreamReady\n")); nsAutoLock lock(mLock); NS_ASSERTION(outStr == mOutput, "unexpected stream"); Process_Locked(); return NS_OK; } void Close_Locked() { LOG(("Close_Locked\n")); mOutput->Close(); mOutput = 0; mInput->Close(); mInput = 0; // post done copying event PostDoneEvent(); } void Process_Locked() { while (1) { mInputCondition = NS_OK; // reset PRUint32 n; nsresult rv = mOutput->WriteSegments(FillOutputBuffer, this, CHUNK_SIZE, &n); if (NS_FAILED(rv) || (n == 0)) { if (rv == NS_BASE_STREAM_WOULD_BLOCK) mOutput->AsyncWait(this, 0, nsnull); else if (mInputCondition == NS_BASE_STREAM_WOULD_BLOCK) mInput->AsyncWait(this, 0, nsnull); else Close_Locked(); break; } } } nsresult AsyncCopy(nsITransport *srcTrans, nsITransport *destTrans) { mLock = PR_NewLock(); if (!mLock) return NS_ERROR_OUT_OF_MEMORY; nsresult rv; nsCOMPtr inStr; rv = srcTrans->OpenInputStream(0, 0, 0, getter_AddRefs(inStr)); if (NS_FAILED(rv)) return rv; nsCOMPtr outStr; rv = destTrans->OpenOutputStream(0, 0, 0, getter_AddRefs(outStr)); if (NS_FAILED(rv)) return rv; mInput = do_QueryInterface(inStr); mOutput = do_QueryInterface(outStr); return mInput->AsyncWait(this, 0, nsnull); } static NS_METHOD FillOutputBuffer(nsIOutputStream *outStr, void *closure, char *buffer, PRUint32 offset, PRUint32 count, PRUint32 *countRead) { MyCopier *self = (MyCopier *) closure; nsresult rv = self->mInput->Read(buffer, count, countRead); if (NS_FAILED(rv)) self->mInputCondition = rv; else if (*countRead == 0) self->mInputCondition = NS_BASE_STREAM_CLOSED; return self->mInputCondition; } protected: PRLock *mLock; nsCOMPtr mInput; nsCOMPtr mOutput; nsresult mInputCondition; }; NS_IMPL_THREADSAFE_ISUPPORTS2(MyCopier, nsIInputStreamNotify, nsIOutputStreamNotify) //////////////////////////////////////////////////////////////////////////////// /** * asynchronously copy file. */ static nsresult RunTest(nsIFile *srcFile, nsIFile *destFile) { nsresult rv; LOG(("RunTest\n")); nsCOMPtr sts = do_GetService(kStreamTransportServiceCID, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr srcStr; rv = NS_NewLocalFileInputStream(getter_AddRefs(srcStr), srcFile); if (NS_FAILED(rv)) return rv; nsCOMPtr destStr; rv = NS_NewLocalFileOutputStream(getter_AddRefs(destStr), destFile); if (NS_FAILED(rv)) return rv; nsCOMPtr srcTransport; rv = sts->CreateInputTransport(srcStr, -1, -1, PR_TRUE, getter_AddRefs(srcTransport)); if (NS_FAILED(rv)) return rv; nsCOMPtr destTransport; rv = sts->CreateOutputTransport(destStr, -1, -1, PR_TRUE, getter_AddRefs(destTransport)); if (NS_FAILED(rv)) return rv; MyCopier *copier = new MyCopier(); if (copier == nsnull) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(copier); rv = copier->AsyncCopy(srcTransport, destTransport); if (NS_FAILED(rv)) return rv; PLEvent* event; gDone = PR_FALSE; while (!gDone) { rv = gEventQ->WaitForEvent(&event); if (NS_FAILED(rv)) return rv; rv = gEventQ->HandleEvent(event); if (NS_FAILED(rv)) return rv; } NS_RELEASE(copier); return NS_OK; } //////////////////////////////////////////////////////////////////////////////// static nsresult RunBlockingTest(nsIFile *srcFile, nsIFile *destFile) { nsresult rv; LOG(("RunBlockingTest\n")); nsCOMPtr sts = do_GetService(kStreamTransportServiceCID, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr srcIn; rv = NS_NewLocalFileInputStream(getter_AddRefs(srcIn), srcFile); if (NS_FAILED(rv)) return rv; nsCOMPtr fileOut; rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOut), destFile); if (NS_FAILED(rv)) return rv; nsCOMPtr destTransport; rv = sts->CreateOutputTransport(fileOut, -1, -1, PR_TRUE, getter_AddRefs(destTransport)); if (NS_FAILED(rv)) return rv; nsCOMPtr destOut; rv = destTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 100, 10, getter_AddRefs(destOut)); if (NS_FAILED(rv)) return rv; char buf[120]; PRUint32 n; for (;;) { rv = srcIn->Read(buf, sizeof(buf), &n); if (NS_FAILED(rv) || (n == 0)) return rv; rv = destOut->Write(buf, n, &n); if (NS_FAILED(rv)) return rv; } return NS_OK; } //////////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { nsresult rv; if (argc < 2) { printf("usage: %s \n", argv[0]); return -1; } char* fileName = argv[1]; { nsCOMPtr servMan; NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); nsCOMPtr registrar = do_QueryInterface(servMan); NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); if (registrar) registrar->AutoRegister(nsnull); #if defined(PR_LOGGING) gTestLog = PR_NewLogModule("Test"); #endif nsCOMPtr eventQService = do_GetService(kEventQueueServiceCID, &rv); if (NS_FAILED(rv)) return rv; rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); if (NS_FAILED(rv)) return rv; nsCOMPtr srcFile; rv = NS_NewNativeLocalFile(nsDependentCString(fileName), PR_FALSE, getter_AddRefs(srcFile)); if (NS_FAILED(rv)) return rv; nsCOMPtr destFile; rv = srcFile->Clone(getter_AddRefs(destFile)); if (NS_FAILED(rv)) return rv; nsCAutoString leafName; rv = destFile->GetNativeLeafName(leafName); if (NS_FAILED(rv)) return rv; nsCAutoString newName; newName = leafName + NS_LITERAL_CSTRING(".1"); rv = destFile->SetNativeLeafName(newName); if (NS_FAILED(rv)) return rv; rv = RunTest(srcFile, destFile); NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); newName = leafName + NS_LITERAL_CSTRING(".2"); rv = destFile->SetNativeLeafName(newName); if (NS_FAILED(rv)) return rv; rv = RunBlockingTest(srcFile, destFile); NS_ASSERTION(NS_SUCCEEDED(rv), "RunBlockingTest failed"); NS_RELEASE(gEventQ); // give background threads a chance to finish whatever work they may // be doing. PR_Sleep(PR_SecondsToInterval(1)); } // this scopes the nsCOMPtrs // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM rv = NS_ShutdownXPCOM(nsnull); NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); return NS_OK; }